有没有办法通过 asyncio 来利用多个 CPU 核心?

all*_*546 8 python windows multiprocessing python-3.x python-asyncio

我用 python 和 asyncio 创建了一个简单的 HTTP 服务器。但是,我读到基于 asyncio 的服务器只能利用一个 CPU 核心。我正在尝试解决这个问题,multiprocessing但它不起作用。当我尝试创建进程时,它给我一个错误,指出它无法从 _winapi 创建进程。到目前为止,这是我的代码:

def serve_forever(self, host, port):
    srv, loop = self.init(host, port)
    print()
    if self.name:
        print('* Serving App {}'.format(self.name))
    print('* Serving On http://{host}:{port}'.format(host=host, port=port))
    print('* Press <CTRL-C> To Quit')
    workers = []
    try:
        for i in range(mp.cpu_count()-1):
            p = mp.Process(target=loop.run_forever)
            workers.append(p)
            p.start()
        loop.run_forever()
    except KeyboardInterrupt:
        print()
        for p in workers:
            p.terminate()
        srv.close()
        loop.run_until_complete(srv.wait_closed())
        loop.close()
        pass
Run Code Online (Sandbox Code Playgroud)

顺便说一句,该self.init功能有效。

Ric*_*unn 10

我认为,您可能有点混淆了并行编程和并发编程。乍一看,它们可能看起来很相似,但您很快就会意识到它们非常不同。

Asyncio 有助于并发,这意味着您可以以非阻塞方式编写代码。换句话说,对于需要时间响应的 I/O 操作(例如网络调用或磁盘访问),您可以让一段特定的代码在等待响应时不阻塞您的进程。这可以为同一线程中代码的其他异步部分释放 CPU 周期。

并行编程涉及将某些较高级别任务的一小部分委派给多个进程或线程,并(通常)在全部完成后收集和合并结果。

以下三种情况有助于区分:

您可以编写一个服务器程序,使收到的每个请求都由一个新线程处理。该线程可能 100% 阻塞,因此如果它进行网络调用或从磁盘读取文件,它将等待 I/O 任务完成。但这没关系,因为它在它自己的线程中,操作系统将负责切换哪些线程在何时运行、在哪些核心上运行等,因此其他线程在该线程等待 I/O 时将有机会运行。这样做的缺点是线程会产生资源开销,并且操作系统并不完全了解线程内发生的情况,它只是尽力确保它们都得到公平的处理。

服务器的另一个版本可以以并发方式编写。这里只使用了一个线程,但是该线程详细了解什么是阻塞的以及什么正在执行(asyncio 来救援),因此您可以编写一次只处理一个请求的代码,但是当给定的请求正在等待时data 它让另一个请求进行一些处理,在任务之间切换,而其他任务则被阻塞,所有这些都在同一个线程/进程内。这是一种更有效的资源利用方式,但它通常只适合高 I/O 工作负载,例如读/写数据库的简单服务器。对于必须为每个请求执行大量大型计算的服务器来说,这并不是很好,因为计算过程中不会有 I/O 事件来触发任务切换。

第三种情况是将这两个概念结合起来。这对于帮助扩展处理大量 I/O 操作的异步服务器很有用。它也可以用于需要处理大量连接和长时间运行的任务的情况,其中任务被委托给线程或其他更复杂的配置,但实际上它对于扩展最有用。

Asyncio 对子进程有一些内置支持

我强烈推荐阅读这篇文章,它非常好。