如何在使用asyncio ProactorEventLoop时分配线程池

时间:2020-06-14 08:03:59

标签: python-asyncio iocp

我当前在Python 3.7中使用asyncio,并使用asyncio.start_server()函数编写一个TCP服务器 请参考以下示例:https://docs.python.org/3/library/asyncio-stream.html

也可以尝试使用“ I / O完成端口”(IOCP)的asyncio.ProactorEventLoop

根据此Microsoft官方文档https://docs.microsoft.com/en-ca/windows/win32/fileio/i-o-completion-ports,它提到将I / O完成端口与预分配的线程池一起使用,但是我找不到在哪里可以分配线程数

在哪里可以分配线程池中的线程数? 有人可以在这里帮我吗?非常感谢!

1 个答案:

答案 0 :(得分:-1)

首先,

有关I / O完成端口( iocp )和线程池的一般信息。我们在这里有2个选项:


自行创建所有内容:

通过CreateIoCompletionPort(或NtCreateIoCompletion)自行

创建 iocp

通过自我创建线程,将其称为GetQueuedCompletionStatus(或NtRemoveIoCompletion)。

您需要通过<{3}}和NtSetInformationFileFileCompletionInformation或通过CreateIoCompletionPort通过FILE_COMPLETION_INFORMATION再次将自己绑定到 iocp (此win32 api结合NtCreateIoCompletionNtSetInformationFile的功能)。


使用系统 iocp 线程池

进程启动时,

系统( ntdll.dll )创建默认线程池(现在名为 TppPoolpGlobalPool )。您可以对此池进行每周控制。您无法获得它的直接指针PTP_POOL。存在未记录的TpSetDefaultPoolMaxThreads(用于设置此池中的最大线程数),但没有用于最小数量的

如果需要-您可以通过CreateThreadpool函数创建其他线程池。

创建新的线程池后,您可以(但不应该!)调用SetThreadpoolThreadMaximum指定该池可以分配的最大线程数,并调用SetThreadpoolThreadMinimum指定可用的最小线程数在游泳池里。

线程池维护一个I / O完成端口。在调用CreateThreadpool中创建的 iocp -我们无法直接访问它。

因此最初在进程中存在一个全局/默认线程池( TppPoolpGlobalPool )和 iocp (用于并行加载程序的Windows 10创建另一个线程池 LdrpThreadPool ,但这当然仅供内部使用-在加载DDL时

最后,您通过调用CreateThreadpoolIo

将自身文件绑定到 iocp

请注意,此处的msdn文档是错误的-

创建一个新的I / O完成对象。

真正的CreateThreadpoolIo函数创建新的I / O完成对象-它仅在调用CreateThreadpool内部创建。此api绑定文件(不是处理文件而是文件!)到与池关联的I / O完成对象。到哪个游泳池?寻找最后一个参数-指向TP_CALLBACK_ENVIRON的可选指针。

您可以通过以下方式指定线程池-分配回调环境,先为其调用InitializeThreadpoolEnvironment,然后再调用SetThreadpoolCallbackPool

如果未指定线程池,则全局线程池将在调用CreateThreadpoolIo中使用-因此文件将绑定到默认/全局进程 iocp

,并且在这种情况下,您不需要自行调用GetQueuedCompletionStatus(或NtRemoveIoCompletion)-系统从池中为您执行此操作。然后调用您的IoCompletionCallback回调函数,该函数将在CreateThreadpoolIo调用中传递给系统


我们还可以通过BindIoCompletionCallback使用系统全局线程池和 iocp ( 或RtlSetIoCompletionCallback)-它将全局( TppPoolpGlobalPool )线程池拥有的I / O完成端口与指定的文件句柄相关联。这是旧的api和情况2的变体。在这里,我们不能使用自定义轮询-只能全局处理。


现在回到具体的Python代码。使用哪种情况?它是自己创建 iocp 和线程池吗?还是使用系统线程池?如果使用系统-使用它由CreateThreadpool分配的全局或自定义线程池?如果您不知道这一点-在这里什么也做不了。并且即使知道..或该库具有特殊的api /接口(或python中的此接口如何调用)也可以控制此(如果使用了self或custom pool),或者您只能按原样使用它。很难决定您池中真正需要多少线程