Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.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实现的简单并发_Python_Python 3.x_Concurrency - Fatal编程技术网

用Python实现的简单并发

用Python实现的简单并发,python,python-3.x,concurrency,Python,Python 3.x,Concurrency,问题的目的:了解更多有关在Python中实现并发的方法/实验 上下文:我想计算与特定模式匹配的所有文件中的所有单词。我的想法是,我可以调用函数count_words('/foo/bar/*.txt'),所有单词(即由一个或多个空格字符分隔的字符串)都将被计数 在实现中,我正在寻找使用并发实现count_words的方法。到目前为止,我设法使用了多处理和asyncio 你有没有看到其他方法来完成同样的任务 我没有使用threading,因为我注意到由于pythongil的限制,性能改进并没有那么显

问题的目的:了解更多有关在Python中实现并发的方法/实验

上下文:我想计算与特定模式匹配的所有文件中的所有单词。我的想法是,我可以调用函数
count_words('/foo/bar/*.txt')
,所有单词(即由一个或多个空格字符分隔的字符串)都将被计数

在实现中,我正在寻找使用并发实现
count_words
的方法。到目前为止,我设法使用了
多处理
asyncio

你有没有看到其他方法来完成同样的任务

我没有使用
threading
,因为我注意到由于pythongil的限制,性能改进并没有那么显著

import asyncio
import multiprocessing
import time
from pathlib import Path
from pprint import pprint


def count_words(file):
    with open(file) as f:
        return sum(len(line.split()) for line in f)


async def count_words_for_file(file):
    with open(file) as f:
        return sum(len(line.split()) for line in f)


def async_count_words(path, glob_pattern):
    event_loop = asyncio.get_event_loop()
    try:
        print("Entering event loop")
        for file in list(path.glob(glob_pattern)):
            result = event_loop.run_until_complete(count_words_for_file(file))
            print(result)
    finally:
        event_loop.close()


def multiprocess_count_words(path, glob_pattern):
    with multiprocessing.Pool(processes=8) as pool:
        results = pool.map(count_words, list(path.glob(glob_pattern)))
        pprint(results)


def sequential_count_words(path, glob_pattern):
    for file in list(path.glob(glob_pattern)):
        print(count_words(file))


if __name__ == '__main__':
    benchmark = []
    path = Path("../data/gutenberg/")
    # no need for benchmark on sequential_count_words, it is very slow!
    # sequential_count_words(path, "*.txt")

    start = time.time()
    async_count_words(path, "*.txt")
    benchmark.append(("async version", time.time() - start))

    start = time.time()
    multiprocess_count_words(path, "*.txt")
    benchmark.append(("multiprocess version", time.time() - start))

    print(*benchmark)
为了模拟大量文件,我从projectgutenberg()下载了一些书籍,并使用以下命令创建了同一文件的多个副本

for i in {000..99}; do cp 56943-0.txt $(openssl rand -base64 12)-$i.txt; done

async def
不会神奇地使函数调用并发,在asyncio中,您需要显式地放弃执行,以便通过对waitables使用
wait
来允许其他协同路由并发运行。也就是说,您当前的
count\u words\u for\u file
仍按顺序执行

您可能希望引入延迟阻塞文件I/O到线程中,从而允许在不同的协程中并发文件I/O。即使这样,计算字数的CPU绑定代码仍然在同一主线程中按顺序运行。要并行化,您仍然需要多个进程和多个CPU(或者多台计算机,请检查)

此外,您的异步IO代码中有一个问题-
用于。。。再次运行_直到_完成
,使函数调用按顺序运行。您需要同时启动它们,并加入结果

import aiofiles

...

async def count_words_for_file(file):
    async with aiofiles.open(file) as f:
        rv = sum(len(line.split()) async for line in f)
        print(rv)
        return rv


async def async_count_words(path, glob_pattern):
    await asyncio.wait([count_words_for_file(file)
                        for file in list(path.glob(glob_pattern))])
    # asyncio.wait() calls loop.create_task() for you for each coroutine

...

if __name__ == '__main__':

    ...

    loop = asyncio.get_event_loop()
    start = time.time()
    loop.run_until_complete(async_count_words(path, "*.txt"))
    benchmark.append(("async version", time.time() - start))

感谢您的评论-我不知道
aiofiles
。我可以请您在回答中添加一些与您建议的更改相关的代码吗?另外,我觉得
event\u loop.run\u直到\u complete
同时运行该函数。当运行代码时,我清楚地看到与纯顺序方法相比的差异。谢天谢地。我还没试过,但你的时间差真的很奇怪。