如何使用所有cpu内核-ProcessPoolExecutor以外的其他选项来使asyncio?
我认为asyncio不能打破GIL限制(也许我错了),因此程序的执行速度将比踩踏版本快,但将在一个内核上执行。
我研究了一些示例,发现其中一种方法是多处理和ProcessPoolExecutor。
https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor
# 3. Run in a custom process pool:
with concurrent.futures.ProcessPoolExecutor() as pool:
result = await loop.run_in_executor(
pool, cpu_bound)
print('custom process pool', result)
这很好,但是在进程之间需要“棘手”,因此需要一些开销和一些优化的传递参数以减少“棘手”序列化。
使用上面的简单模式,我编写了这样的测试代码(如果您不喜欢它,则可以跳过此代码阅读,因为它与以前相同)。顺便说一句,这是我解析文件问题的最快解决方案。这部分代码不是整个程序。
def _match_general_and_specific_file_chunk(file_name):
with codecs.open(file_name, encoding='utf8') as f:
while True:
lines = f.readlines(sizehint=10000)
if not lines:
break
for line in lines:
general_match = RE_RULES.match(line)
if general_match:
specific_match = RULES[general_match.lastindex].match(line)
groups = list(specific_match.groups())
continue
async def _async_process_executor_match_general_and_specific_read_lines_with_limit_file_chunk():
loop = asyncio.get_event_loop()
with ProcessPoolExecutor() as pool:
futures = []
for file_name in get_file_names():
future = loop.run_in_executor(pool, _match_general_and_specific_file_chunk, file_name)
futures.append(future)
await asyncio.gather(*futures)
def async_process_executor_match_general_and_specific_read_lines_with_limit_file_chunk():
asyncio.run(_async_process_executor_match_general_and_specific_read_lines_with_limit_file_chunk())
答案 0 :(得分:4)
如何使用所有cpu内核-ProcessPoolExecutor以外的其他选项来使asyncio?
Asyncio是这项工作的错误工具,因为它专门用于管理IO绑定程序的状态(您可以将其视为Twisted的后继者)。
要并行执行受CPU约束的代码,您将需要线程或进程提供的OS级并发性。在Python中,最方便的方法是concurrent.futures
模块,其中ThreadPoolExecutor
和ProcessPoolExecutor
之类的类首先来自。您只需要submit()
的工作交给执行者,wait
就可以完成最终的期货。
如果要避免酸洗的开销,有两种方法:
使用进程,并在控制进程和工作进程之间使用共享内存,映射的内存或管理器对象share state。
使用线程,但是在执行CPU密集型工作时调用内部释放GIL的代码。一些软件包已经这样做了,例如the hashlib std module或many parts of numpy,但是如果您没有那些软件包无法满足的需求,那将无济于事。在这种情况下,您可能需要编写一个新的C扩展名,有关如何临时释放GIL以及何时可以安全释放GIL的详细信息,请参考the documentation。