Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在Django通道中,线程只能启动一次_Python_Django_Websocket_Django Channels - Fatal编程技术网

Python 在Django通道中,线程只能启动一次

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

我创建了一个简单的Django通道消费者,它应该连接到外部源,检索数据并将其发送到客户端。因此,用户打开页面>消费者连接到外部服务并获取数据>数据发送到websocket

这是我的密码:

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,以便将其用作管理命令,在这种情况下,我将这样做 就像你说的!