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

Bla*_*Box 8 c# multithreading asynchronous async-await .net-4.5

当需要在整个应用程序生命周期中运行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.

Ste*_*ary 7

如果我正确地解释了您的"I/O侦听器",那么您应该始终进行连续的异步读取操作.没有线程是必要的.


nos*_*tio 3

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 
} 
Run Code Online (Sandbox Code Playgroud)

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

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

async Task<Data> 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<bool>();

            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;
    } 
}
Run Code Online (Sandbox Code Playgroud)

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

while (true)
{
    cancellationToken.ThrowIfCancellationRequested();
    var data = await ReadFtdiAsync(cancellationToken);

    // the execution will resume here likely on a different thread
    ProcessData(data);
}
Run Code Online (Sandbox Code Playgroud)