C#Concurrency – 长期运行任务的首选方法

当需要在整个应用程序生命周期中运行I / O侦听器时,在4.5框架上运行C#5.0时,首选哪种并发模型?

我已经确定了生产者 – 消费者模式最适合处理我收到的内容,但基础设施应该支持它的想法?

是否建议使用简单的Thread thread = new Thread(ThreadStart(method)) ? 或者首选的是TaskAsync/Await模型?

这是一个快速解决问题,但由于我在设计初期,我更愿意确保基础强大。 我对其他语言的直觉反应是,在后台运行一个简单的线程是最好的,但C#中过多的并行框架让我偏离了正轨。

如果有任何相关性,我的应用程序中的轮询时间将由I / O读取超时处理。

更新:

I / OI指的是FTDI设备,其中字节可以随时由设备推送到PC,具体取决于板载控制器的状态。 因此,我总是需要准备好拾取数据并进行处理。 我正在使用的API基于FTDI供应商提供的D2XX DLL。

I / OI指的是FTDI设备,其中字节可以随时由设备推送到PC,具体取决于板载控制器的状态。 因此,我总是需要准备好拾取数据并进行处理。 我正在使用的API基于FTDI供应商提供的D2XX DLL。

快速搜索可以发现此文档 。 简要介绍一下它表明您需要打开设备设备以实现重叠I / O,以实现高效的侦听器。 这是文档(C ++)中的相关示例代码:

 FT_HANDLE ftHandle; // setup by FT_W32_CreateFile for overlapped i/o char Buf[256]; DWORD dwToRead = 256; DWORD dwRead; OVERLAPPED osRead = { 0 }; osRead.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); if (!FT_W32_ReadFile(ftHandle, Buf, dwToRead, &dwRead, &osRead)) { if (FT_W32_GetLastError(ftHandle) == ERROR_IO_PENDING) { // write is delayed so do some other stuff until ... if (!FT_W32_GetOverlappedResult(ftHandle, &osRead, &dwRead, FALSE)) { // error } else { if (dwToRead == dwRead) { // FT_W32_ReadFile OK } else { // FT_W32_ReadFile timeout } } } } else { // FT_W32_ReadFile OK } 

这里的关键点是这句评论:“ //写入是延迟所以做其他一些事情,直到…… ”[顺便说一句,我认为这是一个错字,应该是阅读而不是在那里]。

如何处理这种延迟? 要使侦听器异步,您必须异步等待内核事件对象 。 我刚刚回答了一个关于如何有效地做到这一点的相关问题 。 在您的情况下,它可能看起来像这样(C#中的草图):

 async Task ReadFtdiAsync() { // ... var completedMre = new ManualResetEvent(false); osRead.hEvent = completedMre.SafeWaitHandle.DangerousGetHandle(); if (!FT_W32_ReadFile(ftHandle, Buf, dwToRead, ref dwRead, ref osRead)) { if (FT_W32_GetLastError(ftHandle) == ERROR_IO_PENDING) { // asynchronous completion // read is delayed, so await var tcs = new TaskCompletionSource(); ThreadPool.RegisterWaitForSingleObject( completedMre, (s, t) => tcs.SetResult(true), null, Timeout.Infinite, true) // resume asynchronously when the event is signalled await tcs.Task; if (!FT_W32_GetOverlappedResult(ftHandle, ref osRead, ref dwRead, FALSE)) { // error throw new InvalidOperationException("I/O error"); } else { if (dwToRead == dwRead) { // FT_W32_ReadFile OK // retrieve and return the data return data; } else { // FT_W32_ReadFile timeout throw new TimeoutException(); } } } } else { // synchronous completion // retrieve and return the data // or handle an error return data; } } 

可以并且应该使用适当的超时和取消逻辑来改进此代码。 然后你可以简单地在循环中调用ReadFtdiAsync

 while (true) { cancellationToken.ThrowIfCancellationRequested(); var data = await ReadFtdiAsync(cancellationToken); // the execution will resume here likely on a different thread ProcessData(data); } 

如果我正确地解释了您的“I / O侦听器”,那么您应该始终进行连续的异步读取操作。 不需要线程。

对于I / O总是更好地使用.net中的I / O完成端口包装在类似的方法中

 Stream.BeginRead Stream.BeginWrite 

或.net 4.5

 Stream.ReadAsync Stream.WriteAsync 

将线程或任务等待同步I / O操作是一个非常糟糕的主意