Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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 将线程与异步IO结合使用_Python_Multithreading_Python Asyncio - Fatal编程技术网

Python 将线程与异步IO结合使用

Python 将线程与异步IO结合使用,python,multithreading,python-asyncio,Python,Multithreading,Python Asyncio,我一直在寻找一种方法来产生不同的线程(在我的实际程序中,线程的数量在执行过程中可能会发生变化),以执行无休止的运行操作,这将在运行期间(最坏的情况下)阻塞我的整个应用程序几秒钟 因此,我使用标准的线程类和asyncio(因为我的程序的其他部分也在使用它) 这似乎很好用,根据它的说法似乎还可以,但是在搜索异步线程和异步IO时,我经常遇到使用ProcessPoolExecutor的建议(例如在stackoverflow post中)。 现在我想知道,以下方法是否真的是好的做法(甚至是危险的)? 类扫

我一直在寻找一种方法来产生不同的线程(在我的实际程序中,线程的数量在执行过程中可能会发生变化),以执行无休止的运行操作,这将在运行期间(最坏的情况下)阻塞我的整个应用程序几秒钟
因此,我使用标准的线程类和
asyncio
(因为我的程序的其他部分也在使用它)

这似乎很好用,根据它的说法似乎还可以,但是在搜索异步线程和异步IO时,我经常遇到使用
ProcessPoolExecutor
的建议(例如在stackoverflow post中)。 现在我想知道,以下方法是否真的是好的做法(甚至是危险的)?

类扫描程序:
定义初始化(自):
#启动一个新的扫描线程
self.scan_thread=thread(target=self.doScan,args=())
self.scan_thread.start()
def doScan(自身):
打印(“开始扫描”)
loop=asyncio.new\u event\u loop()
循环。运行\u直到完成(self.connection())
打印(“停止扫描”)
_扫描器的列表=[]
列出\u扫描器的\u.append(scanner())
列出\u扫描器的\u.append(scanner())
背景:我自己开始质疑这一点,因为我的程序在生成线程时开始崩溃,主要是错误消息
运行时错误:任务附加到不同的循环
。我知道这与我给你的例子没有直接的联系,但我想我开始用这些线程来搞乱我的异步协同程序


编辑

为了澄清我想补充的内容,我为什么要使用这种奇怪的
asyncio
threads
结构

  • 我正在使用项目的这一部分
    作为线程运行的部分基本上如下所示:
    async def connection():
    x=等待客户端。_是否已连接()
    与作为客户端的BlakClient(地址,loop=loop)异步:
    而x:
    x=等待客户端。_是否已连接()
    log.info(“已连接:{0}”。格式(x))
    
  • endlesscan()
    在做什么? 这个名字有点误导人,在我的代码中它被称为不同的(我现在已经改变了)。新名称是
    connection()

    整个目的是建立到蓝牙设备的链接,基本上监听传入的数据(就像我们使用套接字时所做的那样) 这意味着除非蓝牙设备断开连接,否则将永远不会退出
    loop.run_,直到_完成(self.connection())
  • 为什么我不能创建一个事件循环?
    如前所述,当建立链接时,此功能将无休止地运行。每个连接的设备都运行这样一个无止境的循环。我想在后台做这件事。我的主应用程序不应该等待例程完成,并且在任何情况下都必须响应。对我来说,这证明了将
    线程
    异步IO
    结合使用是合理的

  • 编辑2:根据@user4815162342建议添加了我的测试代码。 死刑似乎很有效

    导入异步IO
    从线程导入线程、事件、锁
    随机输入
    类别扫描程序:
    定义初始化(自我、id、循环):
    打印(“初始%s”%id)
    self.id=id
    self.submit\u async(self.update\u raw\u data(),循环)
    self.raw_data=“”
    self.event=event()
    self.data_lock=lock()
    @财产
    def原始数据(自身):
    使用self.data\u锁:
    返回自己的原始数据
    @原始数据设置器
    def原始数据(自身、原始数据):
    self.\u raw\u data=原始数据
    def提交异步(自、等待、循环):
    返回asyncio.run\u coroutine\u threadsafe(可等待,循环)
    异步def更新原始数据(自):
    尽管如此:
    使用self.data\u锁:
    self.\u raw\u data=random.random()
    打印(“唤醒%s和%s”%(self.id,self.\u原始数据))
    等待asyncio.sleep(self.id)
    def_start_async():
    loop=asyncio.new\u event\u loop()
    t=线程(目标=循环。永远运行)
    t、 daemon=True
    t、 开始()
    回路
    _循环=\u开始\u异步()
    def stop_async():
    _loop.call\u soon\u threadsafe(\u loop.stop)
    ble_设备=[扫描仪(1,_循环)、扫描仪(2,_循环)、扫描仪(4,_循环)]
    #此代码从不执行。。。
    对于ble_设备中的开发人员:
    打印(开发原始数据)
    
    我建议在后台线程中创建一个事件循环,并让它满足您所有的异步需求。你的合作永远不会结束并不重要;asyncio完全能够并行执行多个这样的函数

    例如:

    def _start_async():
        loop = asyncio.new_event_loop()
        threading.Thread(target=loop.run_forever).start()
        return loop
    
    _loop = start_async()
    
    # Submits awaitable to the event loop, but *doesn't* wait for it to
    # complete. Returns a concurrent.futures.Future which *may* be used to
    # wait for and retrieve the result (or exception, if one was raised)
    def submit_async(awaitable):
        return asyncio.run_coroutine_threadsafe(awaitable, _loop)
    
    def stop_async():
        _loop.call_soon_threadsafe(_loop.stop)
    
    有了这些工具(可能在单独的模块中),您可以执行以下操作:

    class Scanner:
        def __init__(self):
            submit_async(self.connection())
            # ...
    
        # ...
    
    • 关于使用
      ProcessPoolExecutor
      的建议如何
    这些应用于在并行进程中运行CPU绑定的代码,以避免GIL。如果您实际运行的是异步代码,则不应该关心
    ProcessPoolExecutor

    • 使用
      ThreadPoolExecutor
      的建议是什么

    ThreadPoolExecutor
    只是一个对经典多线程应用程序有用的线程池。在Python中,它主要用于使程序更具响应性,而不是使程序更快。它允许您与交互代码并行运行CPU绑定或阻塞代码,而不会导致饥饿。由于GIL,它不会使事情更快。

    我建议在后台线程中创建一个事件循环,并让它满足您所有的异步需求。你的合作永远不会结束并不重要;asyncio完全能够并行执行多个这样的函数

    例如:

    def _start_async():
        loop = asyncio.new_event_loop()
        threading.Thread(target=loop.run_forever).start()
        return loop
    
    _loop = start_async()
    
    # Submits awaitable to the event loop, but *doesn't* wait for it to
    # complete. Returns a concurrent.futures.Future which *may* be used to
    # wait for and retrieve the result (or exception, if one was raised)
    def submit_async(awaitable):
        return asyncio.run_coroutine_threadsafe(awaitable, _loop)
    
    def stop_async():
        _loop.call_soon_threadsafe(_loop.stop)
    
    有了这些工具(可能在单独的模块中),您可以执行以下操作:

    class Scanner:
        def __init__(self):
            submit_async(self.connection())
            # ...
    
        # ...
    
    • 你给我的建议是什么