.Net Thread vs ThreadPool vs SerialPort Communication的任务

Ver*_*rax 5 .net multithreading task threadpool

我在C#.Net 4.0应用程序中使用SerialPort类和s ThreadPool.QueueUserWorkItem或者Tasks 遇到了一个有趣的问题.

如果我同时使用2个或更多SerialPort,则只会出现此问题.每个串口都在自己的线程中运行,我以3种方式之一创建:

  1. new Thread(DoSerialCommX)
  2. ThreadPool.QueueUserWorkItem(DoSerialCommX)
  3. new Task(DoSerialCommX, TaskCreationOptions.LongRunning).Start()

为了说明这个问题,我创建了我的DoSerialCommX方法来永久地在循环中读取和写入串行端口.它看起来像这样:(我实际上并没有在我的真实程序中执行此操作.这只是我的测试程序中的一个片段,它隔离并说明了问题).

private void DoSerialCommX()
{
    SerialPort port = new SerialPort("ComX", 9600);
    port.Open();

    while(true)
    {
        //Read and write to serial port
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我使用方法2或3,串行通信口吃,我收到很多通信超时.如果我使用方法1,一切都很好.此外,我应该提到这似乎只发生在我的基于英特尔凌动的PC上.台式电脑似乎没有问题.

我知道线程池重用了线程,默认情况下Task使用线程池.我知道线程池真正用于短期操作.但我尝试使用TaskCreationOptions.LongRunning,我认为会产生一个专用线程,而不是使用线程池,但它仍然无法正常工作.

所以这个问题: 是什么让Thread在这种情况下如此特别?有什么东西Thread使它更适合IO操作吗?

编辑: 到目前为止,答案似乎假设我正在尝试使用ThreadPool或任务进行永无止境的过程.在我的实际应用中,情况并非如此.我只是在上面的代码中使用了一个永无止境的循环来说明问题.我真的需要知道为什么Thread有效ThreadPool,Task有无.什么在技术上不同会导致串行通信打嗝?

ste*_*hbu 2

从理论上讲,1、2 和 3 之间执行线程的行为方式几乎没有什么区别。它们都共享相同的默认执行优先级,除非您覆盖它 - 理论上线程调度程序将使用相同的策略来调度它们。他们都会高兴地坐在圆圈里旋转。

我怀疑方法之间更大的区别是:

  1. 基础设施成本(线程、内存等)用于支持 #2 和 #3 的线程池,所有这些都将与执行循环争夺时钟时间片。
  2. 肌肉较少的 Atom 上的线程上下文切换成本。Atom 具有较小的缓存和较短的处理管道。更多运行的线程=更多的上下文切换、更多的管道转储和降低的指令缓存效率。

从功能的角度来看,使用方法 2 和 3 有点滥用 - 您的意图是永远不退出该方法。这些策略针对原子、有限操作以及通常适合 IO 完成端口任务(例如异步网络、磁盘操作等)的无引导执行进行了优化...(也许您的串行端口代码也有可能?)

除非您有兴趣适应异步 IO,否则我会跳过 2 和 3。专注于线程 - 似乎您想要更细粒度、可预测的执行控制,而不需要线程池带来的基础设施开销。