Python 在Django通道中,线程只能启动一次
我创建了一个简单的Django通道消费者,它应该连接到外部源,检索数据并将其发送到客户端。因此,用户打开页面>消费者连接到外部服务并获取数据>数据发送到websocket 这是我的密码:Python 在Django通道中,线程只能启动一次,python,django,websocket,django-channels,Python,Django,Websocket,Django Channels,我创建了一个简单的Django通道消费者,它应该连接到外部源,检索数据并将其发送到客户端。因此,用户打开页面>消费者连接到外部服务并获取数据>数据发送到websocket 这是我的密码: import json from channels.generic.websocket import WebsocketConsumer, AsyncConsumer, AsyncJsonWebsocketConsumer from binance.client import Client import js
import json
from channels.generic.websocket import WebsocketConsumer, AsyncConsumer, AsyncJsonWebsocketConsumer
from binance.client import Client
import json
from binance.websockets import BinanceSocketManager
import time
import asyncio
client = Client('', '')
trades = client.get_recent_trades(symbol='BNBBTC')
bm = BinanceSocketManager(client)
class EchoConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
await self.send_json('test')
bm.start_trade_socket('BNBBTC', self.process_message)
bm.start()
def process_message(self, message):
JSON1 = json.dumps(message)
JSON2 = json.loads(JSON1)
#define variables
Rate = JSON2['p']
Quantity = JSON2['q']
Symbol = JSON2['s']
Order = JSON2['m']
asyncio.create_task(self.send_json(Rate))
print(Rate)
当我打开一页时,此代码起作用;但是,如果我尝试使用新帐户打开新窗口,它将抛出以下错误:
File "C:\Users\User\Desktop\Heroku\github\master\myapp\consumers.py", line 54, in connect
bm.start()
File "C:\Users\User\lib\threading.py", line 843, in start
raise RuntimeError("threads can only be started once")
threads can only be started once
我不熟悉频道,所以这是一个noob问题,但我如何解决这个问题?我想做的是:用户打开页面并获取数据,另一个用户打开页面并获取数据;没有办法吗?或者我只是误解了Django频道和websockets的工作原理?我不是Django开发者,但如果我理解正确,函数connect被调用了不止一次,而bm.start引用的线程很可能是在bm.start\u trade\u socket或connect中的其他地方创建的。总之,当调用bm.start时,会启动一个线程,当再次调用时,会出现错误。我不是Django开发人员,但如果我理解正确,函数connect会被多次调用,而bm.start引用的线程很可能是在bm.start\u trade\u socket或connect中的其他地方创建的。总之,当bm.start被调用时,一个线程被启动,当它再次被调用时,就会出现错误。这里开始线程的活动 每个线程对象最多应调用一次。您已将BinanceSocketManager的全局对象设置为bm 如果在同一线程对象上调用多次,它将始终引发运行时错误 请参考下面提到的代码,它可能会帮助您
from channels.generic.websocket import WebsocketConsumer, AsyncConsumer, AsyncJsonWebsocketConsumer
from binance.client import Client
import json
from binance.websockets import BinanceSocketManager
import time
import asyncio
class EchoConsumer(AsyncJsonWebsocketConsumer):
client = Client('', '')
trades = client.get_recent_trades(symbol='BNBBTC')
bm = BinanceSocketManager(client)
async def connect(self):
await self.accept()
await self.send_json('test')
self.bm.start_trade_socket('BNBBTC', self.process_message)
self.bm.start()
def process_message(self, message):
JSON1 = json.dumps(message)
JSON2 = json.loads(JSON1)
#define variables
Rate = JSON2['p']
Quantity = JSON2['q']
Symbol = JSON2['s']
Order = JSON2['m']
asyncio.create_task(self.send_json(Rate))
print(Rate)
在这里开始线程的活动 每个线程对象最多应调用一次。您已将BinanceSocketManager的全局对象设置为bm 如果在同一线程对象上调用多次,它将始终引发运行时错误 请参考下面提到的代码,它可能会帮助您
from channels.generic.websocket import WebsocketConsumer, AsyncConsumer, AsyncJsonWebsocketConsumer
from binance.client import Client
import json
from binance.websockets import BinanceSocketManager
import time
import asyncio
class EchoConsumer(AsyncJsonWebsocketConsumer):
client = Client('', '')
trades = client.get_recent_trades(symbol='BNBBTC')
bm = BinanceSocketManager(client)
async def connect(self):
await self.accept()
await self.send_json('test')
self.bm.start_trade_socket('BNBBTC', self.process_message)
self.bm.start()
def process_message(self, message):
JSON1 = json.dumps(message)
JSON2 = json.loads(JSON1)
#define variables
Rate = JSON2['p']
Quantity = JSON2['q']
Symbol = JSON2['s']
Order = JSON2['m']
asyncio.create_task(self.send_json(Rate))
print(Rate)
你真的需要一个辅助线程吗
class EchoConsumer(AsyncJsonWebsocketConsumer):
symbol = ''
async def connect(self):
self.symbol = 'BNBBTC'
# or, more probably, retrieve the value for "symbol" from query_string
# so the client can specify which symbol he's interested into:
# socket = new WebSocket("ws://.../?symbol=BNBBTC");
await self.accept()
def process_message(self, message):
# PSEUDO-CODE BELOW !
if self.symbol == message['symbol']:
await self.send({
'type': 'websocket.send',
'text': json.dumps(message),
})
为了获得额外的灵活性,您还可以接受客户端的所有符号列表,而不是:
//HTML
socket = new WebSocket("ws://.../?symbols=XXX,YYY,ZZZ");
然后在消费者中:
class EchoConsumer(AsyncJsonWebsocketConsumer):
symbols = []
async def connect(self):
# here we need to parse "?symbols=XXX,YYY,ZZZ" ...
# the code below has been stolen from another project of mine and should be suitably adapted
params = urllib.parse.parse_qs(self.scope.get('query_string', b'').decode('utf-8'))
try:
self.symbols = json.loads(params.get('symbols', ['[]'])[0])
except:
self.symbols = []
def process_message(self, message):
if message['symbol'] in self.symbols:
...
你真的需要一个辅助线程吗
class EchoConsumer(AsyncJsonWebsocketConsumer):
symbol = ''
async def connect(self):
self.symbol = 'BNBBTC'
# or, more probably, retrieve the value for "symbol" from query_string
# so the client can specify which symbol he's interested into:
# socket = new WebSocket("ws://.../?symbol=BNBBTC");
await self.accept()
def process_message(self, message):
# PSEUDO-CODE BELOW !
if self.symbol == message['symbol']:
await self.send({
'type': 'websocket.send',
'text': json.dumps(message),
})
为了获得额外的灵活性,您还可以接受客户端的所有符号列表,而不是:
//HTML
socket = new WebSocket("ws://.../?symbols=XXX,YYY,ZZZ");
然后在消费者中:
class EchoConsumer(AsyncJsonWebsocketConsumer):
symbols = []
async def connect(self):
# here we need to parse "?symbols=XXX,YYY,ZZZ" ...
# the code below has been stolen from another project of mine and should be suitably adapted
params = urllib.parse.parse_qs(self.scope.get('query_string', b'').decode('utf-8'))
try:
self.symbols = json.loads(params.get('symbols', ['[]'])[0])
except:
self.symbols = []
def process_message(self, message):
if message['symbol'] in self.symbols:
...
嘿,谢谢你的回答!我试过了,但是我得到了同样的错误!嘿,谢谢你的回答!我试过了,但是我得到了同样的错误!是的,这正是你所说的;不幸的是,我对异步代码和WebSocket的了解还很少,所以我认为消费者会将数据发送给每个用户是的,这正是你所说的;不幸的是,我对异步代码和WebSocket的了解还很少,所以我认为消费者会将数据发送给每个用户。注释不是用于扩展讨论;这个对话已经结束了。@Mario Orlandi我可能解决了这个问题!!以下是我所做的:我在Django Channel应用程序上创建了两个消费者,其中一个用于在页面打开时订阅用户,因此,如果用户打开市场“BTCUSD”,则该用户将订阅组“BTCUSD”。另一个消费者只从Django Collector接收数据,对于从Django Collector接收到的每一笔交易,它都会读取交易名称并将其广播到正确的组!美好的然而,我不理解第二个消费者的需求。Django收集器可能会通过itself@MarioOrlandi第二个消费者的需求来自这样一个事实:data collector托管在另一台服务器上,因此它无法将数据直接发送到我的Django频道组,因为Django托管在不同的服务器上。我计划将data collector移动到Django,这样我就可以将其用作管理命令,在这种情况下,我将按照您所说的做!评论不用于扩展讨论;这个对话已经结束了。@Mario Orlandi我可能解决了这个问题!!以下是我所做的:我在Django Channel应用程序上创建了两个消费者,其中一个用于在页面打开时订阅用户,因此,如果用户打开市场“BTCUSD”,则该用户将订阅组“BTCUSD”。另一个消费者只从Django Collector接收数据,对于从Django Collector接收到的每一笔交易,它都会读取交易名称并将其广播到正确的组!美好的然而,我不理解第二个消费者的需求。Django收集器可能会通过itself@MarioOrlandi第二个消费者的需求来自这样一个事实:data collector托管在另一台服务器上,因此它无法将数据直接发送到我的Django频道组,因为Django托管在不同的服务器上。我计划将data collector移动到Django,以便将其用作管理命令,在这种情况下,我将这样做 就像你说的!