Channels는 Django를 확장해 웹소켓과 같이 HTTP가 아닌 프로토콜을 핸들링할 수 있게 돕고 비동기적인 처리를 가능하게 해주는 ASGI의 구현체로, 장고를 이용한 실시간 채팅 구현 등에 활용할 수 있습니다. 이 글은 채널즈의 공식 문서를 최대한 원어를 살려 번역한 글입니다. 다소 의역하거나 생략한 부분이 있을 수 있음을 너그러이 양해해주시고, 잘못을 자유롭게 지적해주시면 감사하겠습니다.
튜토리얼 2에서 이어집니다.
이제 성능 향상을 위해 동기적으로 작성된 컨슈머 코드를 비동기적으로 다시 작성해 봅시다.
우리가 만든 ChatConsumer
는 동기적으로 작동합니다. 동기적인 컨슈머는 장고 모델 접근과 같은 일반적인 동기적 입출력 함수들을 별다른 처리 없이 사용할 수 있어서 편리합니다. 하지만 비동기적인 컨슈머들은 요청을 처리할 때 별도의 쓰레드를 만들 필요가 없어 훨씬 우수한 성능을 자랑합니다.
ChatConsumer
는 그 자체로 비동기적인 라이브러리(채널즈와 채널 레이어)만을 사용하고, 특히 장고 모델에 접근하지 않기 때문에 간단하게 비동기적으로 다시 작성할 수 있습니다.
주의사항
ChatConsumer
가 장고 모델이나 다른 동기적인 코드에 접근한다 하더라도 비동기적으로 만들 수 있습니다.asgiref.sync.sync_to_async
나channels.db.database_sync_to_async
와 같은 유틸 함수들은 비동기적인 컨슈머에서 동기적인 코드를 실행하기 위해 사용할 수 있습니다. 하지만 비동기적인 컨슈머에서 얻을 수 있는 성능 향상의 정도는 그 자체로 비동기적인 라이브러리만 사용할 때에 비해 다소 줄어듭니다.
ChatConsumer
를 비동기적으로 다시 작성해 봅시다. 다음 코드를 chat/consumers.py
에 붙여넣습니다:
# chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
# Receive message from room group
async def chat_message(self, event):
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
위 코드의 ChatConsumer
는 기존의 ChatConsumer
와 다음 차이점만 제외하면 거의 비슷해 보입니다:
ChatConsumer
는 이제 WebsocketConsumer
가 아닌 AsyncWebsocketConsumer
를 상속받습니다.def
가 아니라 async def
입니다.await
가 사용되었습니다.async_to_sync
가 더이상 필요하지 않습니다.이제 /ws/chat/ROOM_NAME/
에 해당하는 새 컨슈머가 잘 동작하는지 확인해 봅시다. 채널즈 개발 서버 실행을 위해 다음 커맨드를 입력합니다:
$ python3 manage.py runserver
브라우저를 열고 채팅방 페이지 http://127.0.0.1:8000/chat/lobby/
로 이동합니다. 다른 탭을 하나 더 열어 동일한 채팅방 페이지로 이동합니다.
이제 두번째 브라우저 탭에서, “비동기 안녕!”이라고 타이핑하고 엔터를 눌러보세요. 그러면 두번째 탭과 첫번째 탭 모두에서 "비동기 안녕!"이라는 메시지가 채팅 로그에 나타나는 것을 확인하실 수 있습니다.
이제 이 채팅 서버는 완전히 비동기적입니다!
이 튜토리얼은 튜토리얼 4로 이어집니다.