use*_*000 7 .net c# multithreading asynchronous async-await
我想了解I/O完成端口,具体如何与使用async- await为I/O.
臭名昭着的文章没有线程谈论在I/O完成后短暂借用IOCP.因为本文的重点是要表明当花哨的硬件级I/O内容在飞行中时,没有一个线程被循环消耗
I/O完成了吗?没有.I/O已经完成了吗?没有.I/O已经完成了吗?不...
但后来我正在看这篇文章说的那个
"组件负责检查排队元素的完成端口"
并给出一个例子
public class IOCompletionWorker
{
public unsafe void Start(IntPtr completionPort)
{
while (true)
{
uint bytesRead;
uint completionKey;
NativeOverlapped* nativeOverlapped;
var result = Interop.GetQueuedCompletionStatus(
completionPort,
out bytesRead,
out completionKey,
&nativeOverlapped,
uint.MaxValue);
var overlapped = Overlapped.Unpack(nativeOverlapped);
if (result)
{
var asyncResult = ((FileReadAsyncResult)overlapped.AsyncResult);
asyncResult.ReadCallback(bytesRead, asyncResult.Buffer);
}
else
{
ThreadLogger.Log(Interop.GetLastError().ToString());
}
Overlapped.Free(nativeOverlapped);
}
}
}
Run Code Online (Sandbox Code Playgroud)
var completionPortThread = new Thread(() => new IOCompletionWorker().Start(completionPortHandle))
{
IsBackground = true
};
completionPortThread.Start();
Run Code Online (Sandbox Code Playgroud)
对我来说,看起来有一些民意调查正在进行中.
我想我的问题归结为
两篇文章都以自己的方式是正确的.
IOCP不是线程.它们可以被视为某种队列,其中内核(或者常规用户模式代码,通过PostQueuedCompletionStatus)可以发布完成项.没有与IOCP本身相关的固有线程模型或线程,它们只是多个生产者 - 消费者队列.
我们以网络套接字为例,但对于任何类型的异步工作都是如此:
在任何此操作中都没有涉及您的进程的实际用户模式线程(除了初始异步调用之外).如果你想对你的数据到达这一事实采取行动(我假设你在从套接字读取时就这样做了!),那么你必须从IOCP中将已完成的项目出列.
IOCP的关键是您可以将数千个IO句柄(套接字,文件......)绑定到单个IOCP.然后,您可以使用单个线程并行驱动数千个异步进程.
是的,执行GetQueuedCompletionStatus的一个线程被封锁,而IOCP上没有完成待处理,所以这可能是你的混乱所在.但IOCP的关键在于您阻止了一个线程,而您可以在任何给定时间处理数十万个网络操作,所有这些都由您的一个线程提供服务.你永远不会在IO句柄/ IOCP /服务线程之间进行1对1对1的映射,因为那样你就会失去异步的任何好处,你也可以只使用同步IO.
IOCP的主要目的是在Windows下实现令人印象深刻的异步操作并行性.
我希望这能澄清这种混乱.
至于具体问题
纯托管异步操作(例如,使用Task.Delay执行async-await)不涉及任何IO句柄,因此它们最终不会被某个驱动程序发布到IOCP,因此这些操作将属于"工人"类别.
作为旁注,您可以通过其callstack告诉来自IO线程的Worker线程.工作线程将使用"ThreadPoolWorkQueue.Dispatch"启动其托管调用堆栈,而IO线程将使用"_IOCompletionCallback.PerformIOCompletionCallback"启动其托管调用堆栈.这是可以随时更改的所有实现细节,但在调试托管代码时了解您正在处理的内容会很有帮助.
| 归档时间: |
|
| 查看次数: |
553 次 |
| 最近记录: |