ThreadPool.QueueUserWorkItem - 顺序不保证?

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

这个名称表明顺序是被保留的。

有没有办法确保顺序被保留?
如果没有,您建议采用什么替代实现方法?


具体指什么顺序?开始任务吗? - Jon
@Jon:它们被排队的顺序。 - Daniel Hilgarth
4个回答

6

无法保留顺序。线程池的目的是并行执行独立任务。那些任务开始和结束的顺序本质上高度不确定性。如果您需要子任务按特定顺序开始和完成,则无法将它们并行化。

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

    Thread.Sleep(1000);
}

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

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

谢谢,这正是我所需要的。 - Daniel Hilgarth

4

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

如果要保留顺序,一种选择是逐个运行工作项,而不是从线程池中运行。另一种选择是在第一个工作中内部安排第二个工作,依此类推... 或者使用等待句柄来同步工作。


1

名称表明顺序得到保留。

'queue' 在名称中表示将项目排队以在线程池线程中执行。这意味着 - 如果除一个之外的所有线程池线程都忙 - 在这种情况下,您的项目将按照您排队的顺序依次排队。但由于这不太可能发生,因此项目将首先进入可用的后台线程,然后并发执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接