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
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())
# ...
# ...
- 你给我的建议是什么