簡體   English   中英

避免“兩個事件循環試圖同時在一個通道層上接收()!” Django 頻道錯誤

[英]Avoiding the "Two event loops are trying to receive() on one channel layer at once!" error with Django Channels

簡而言之:我正在嘗試讓 Django 通道消費者與單獨的邏輯線程進行通信。

不管我在下面問什么,除了 Django-Channels 之外,我可能還需要考慮一個更適合的選項。 我的目標是:

  • 我想以編程方式啟動邏輯線程,這就是 Django-Channels 工作線程對我不起作用的原因。
  • 我希望邏輯線程能夠向消費者發送數據
  • 我希望消費者能夠將數據發送到邏輯線程
  • 我不想在(例如)“主機”消費者中處理游戲邏輯,因為如果主機必須重新連接他們的 websocket,游戲就會崩潰

更長的版本:假設我正在嘗試在網站上制作一個簡單的游戲,該游戲使用 websockets 在前端和后端之間進行通信。 使用 Django 頻道,這可以很容易地設置。

但是,當我需要處理游戲邏輯時,我想在某個中央線程中計算它,該線程不會在客戶端斷開連接時停止。 我發現您可以從消費者 scope here之外的任意線程與消費者進行通信。 但是,這有一個問題:

  • 游戲邏輯可以輕松地向客戶端發送信息,但客戶端無法將信息發回。
  • 如果我們使用 RESTful API 讓客戶端向游戲邏輯線程發送信息,速度會很慢,而且我們無法使用consumer.disconnect()來干凈地處理客戶端斷開連接。
  • 當嘗試在游戲邏輯線程中使用async_to_sync(self.channel_layer.receive)(...)時,會導致以下錯誤: Two event loops are trying to receive() on one channel layer at once! 很明顯, RedisChannelLayer並沒有單獨的線程監聽事件。

因此,我認為我需要找到另一種方法來以某種方式將信息從消費者發送到其他線程。 換句話說,在下面的代碼片段中:

class GameClientConsumer(JsonWebsocketConsumer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

def connect(self):
    # Accept the websocket connection.
    self.accept()

def receive_json(self, content=None, **kwargs):
    # Handle player input
    send_information_to_another_thread(data)

我需要找到send_information_to_another_thread(data)的樣子。 這可能嗎? 或者,我想了解如何以某種方式從任意線程的通道層receive()事件。

根據您的解釋,您似乎需要兩件事:

  1. 從消費者外部向通道層發送消息。 正如您所說,您已經在文檔中找到了這一點。

  2. 將消息從消費者發送到另一個線程或代碼塊。 消費者代碼就像任何其他 Python 代碼一樣,因此您可以從中調用任意 function。 當然,您應該注意不要阻塞事件循環,因此應該將消費者外部的繁重邏輯分配給另一個進程或線程。 您可以將該外部邏輯放入 celery 任務中,例如,如果它很重,只需像調用任何其他 celery 任務一樣簡單地調用該任務。 本質上:

     def receive_json(self, content=None, **kwargs): # Handle player input celery_task.delay(**kwargs)

這樣,每次您收到新消息時都會運行該任務。 如果您有很多這樣的任務,您可以在收到新消息時觸發 Django 信號,然后處理程序可以決定如何處理它(觸發 celery 任務,運行一個小邏輯並返回,向消費者發回一些消息, ETC)

不需要通過通道層調用receive function。 相反,將消息從接收 function 推送到需要它們的服務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM