4

我刚刚注意到,排队的回调顺序ThreadPool.QueueUserWorkItem不是确定性的,它肯定不是传入回调的顺序。

这可以通过以下简单程序进行验证:

    private static void Main()
    {
        for (var i = 0; i < 10; ++i)
            ThreadPool.QueueUserWorkItem(Console.Write, i + " ");

        Thread.Sleep(1000);
    }

一次运行的输出是:

0 3 8 9 1 2 5 4 6 7

顾名思义,订单被保留。

有没有办法确保订单被保留?
如果不是,您建议采用什么替代实施方式?

4

4 回答 4

6

没有办法保持顺序。线程池的目的是并行执行独立的任务。这些任务开始和完成的顺序本质上是高度不确定的。如果您需要子任务以特定顺序开始和完成,那么您无法将它们并行化。

private static void Main()
{
    for (var i = 0; i < 10; ++i)
        Console.Write(i + " ");

    Thread.Sleep(1000);
}

澄清一下:线程池队列中的任务顺序被保留,但它们实际执行的顺序是不确定的。

于 2013-01-24T16:25:36.087 回答
6

如果您希望任务在与调用线程不同的线程上串行运行,那么您应该查看Reactive Extensions中的EventLoopScheduler。它允许您在特定工作线程上安排工作单元。

于 2013-01-24T16:30:12.150 回答
4

我不确定是否保留了启动任务的顺序。但是,由于所有排队的工作项都是异步运行的,因此无论如何您都无法保证执行顺序。

如果要保留顺序,一种选择是串行运行工作项,而不是从线程池中运行。另一个是在第一个作业中安排第二个作业,等等......还有一个是使用等待句柄来同步工作。

于 2013-01-24T16:26:25.430 回答
1

顾名思义,订单被保留。

名称中的“队列”表示项目在线程池线程中排队等待执行。这意味着 - 如果线程池线程除一个外都忙 - 在这种情况下,您的项目将按顺序一个接一个地排队你让他们排队。但因为这不太可能项目将首先进入可用的后台线程,然后同时执行。

于 2013-02-02T04:43:59.240 回答