前回のおさらい
前回は実際にWebSocketでチャットを実装しました.が,実はあのconsumerは同期的に動いていたため,今回は非同期で書き直します.
Tutorial Part 3: Rewrite Chat Server as Asynchronous
consumerを非同期に書き直す
同期的に動作することの
- メリット
- Djangoモデルへのアクセスについて,特にコード追加せずに可能
- デメリット
- パフォーマンスが低くなる
非同期的に動作することについてはこれらのメリット,デメリットの逆が言えます.データベースアクセスを伴うような動作においてはasgiref.sync.sync_to_async
やchannels.db.database_sync_to_async
などを使用することで非同期処理に変更できますが,パフォーマンスの向上は完全にネイティブな非同期処理と比べると劣ります.
今回のChatConsumer
はデータベースアクセスを伴わないため,完全に非同期に書き直すことが出来ます.
from channels.generic.websocket import AsyncWebsocketConsumer import json 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 self.room_group_name = 'chat_{}'.format(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
の継承元がWebsocketConsumer
からAsyncWebsocketConsumer
に- Python3.5から導入された
async
/await
を用いたIO周りの非同期化*1 async_to_sync
は必要なくなったので削除
といった感じです.このように完全非同期処理で書くことができ,パフォーマンスが向上します,
runserverして動作するかを確かめます.
$ python manage.py runserver
またタブを複数開いて実行してみます(前回と同様なので省略).
このチュートリアルを書いた人はもう少し各章のバランスを取った方がいいと思います(笑) 次回,チュートリアル最後のPart4に続きます.