ぽよメモ

レガシーシステム考古学専攻

Django 2.0 + Channels 2.1 でチュートリアルやっていく(3)

前回のおさらい

poyo.hatenablog.jp

前回は実際にWebSocketでチャットを実装しました.が,実はあのconsumerは同期的に動いていたため,今回は非同期で書き直します.

Tutorial Part 3: Rewrite Chat Server as Asynchronous

consumerを非同期に書き直す

同期的に動作することの

  • メリット
    • Djangoモデルへのアクセスについて,特にコード追加せずに可能
  • デメリット
    • パフォーマンスが低くなる

非同期的に動作することについてはこれらのメリット,デメリットの逆が言えます.データベースアクセスを伴うような動作においてはasgiref.sync.sync_to_asyncchannels.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に続きます.