【问题标题】:Why the thread pool can launch my tasks with the same priority not in the same order I posted them?为什么线程池可以以相同的优先级启动我的任务,而不是按照我发布它们的顺序?
【发布时间】:2018-04-28 07:00:06
【问题描述】:

我始终通过线程池运行三个操作。它们具有相同的优先级。但是,它们的执行顺序并不总是我运行它们的顺序。为什么会这样?

我预计线程池将按照我将它们发布到线程池的查询队列中的顺序启动我的任务(如果它们具有相同的优先级)。

using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;

namespace ThreadsLearning {

    class Foo {
        public string Name { get; set; }

        public override string ToString() {
            return Name;
        }
    }

    class Program {

        private static void Main(string[] args) {

            Console.WriteLine("Main method works...");

            Foo foo = new Foo { Name = "Bob" };

            CallContext.LogicalSetData("name", foo);

            ThreadPool.QueueUserWorkItem(state => Console.WriteLine("1: Name = {0}",
            CallContext.LogicalGetData("name")));

            ExecutionContext.SuppressFlow();

            ThreadPool.QueueUserWorkItem(state => Console.WriteLine("2: Name = {0}",
                CallContext.LogicalGetData("name")));

            ExecutionContext.RestoreFlow();

            ThreadPool.QueueUserWorkItem(state => Console.WriteLine("3: Name = {0}",
                CallContext.LogicalGetData("name")));

            Console.WriteLine("Hit <Enter> for exit...");
            Console.ReadLine();
        }
    }
}

输出可以是:

Main method works...
Hit <Enter> for exit...
2: Name =
1: Name = Bob
3: Name = Bob

Main method works...
1: Name = Bob
2: Name =
3: Name = Bob
Hit <Enter> for exit...

UPD

我尝试对流做同样的事情并遇到同样的问题:

using System;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;

namespace ThreadsLearning {

    class Foo {
        public string Name { get; set; }

        public override string ToString() {
            return Name;
        }
    }

    class Program {

        private static void Main(string[] args) {

            using (MemoryStream ms = new MemoryStream()) {

                using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8, 0x1000, true)) {
                    sw.WriteLine("Main method works...");

                    Foo foo = new Foo { Name = "Bob" };

                    CallContext.LogicalSetData("name", foo);

                    ThreadPool.QueueUserWorkItem(state => sw.WriteLine("1: Name = {0}",
                        CallContext.LogicalGetData("name")));

                    ExecutionContext.SuppressFlow();

                    ThreadPool.QueueUserWorkItem(state => sw.WriteLine("2: Name = {0}",
                        CallContext.LogicalGetData("name")));

                    ExecutionContext.RestoreFlow();

                    ThreadPool.QueueUserWorkItem(state => sw.WriteLine("3: Name = {0}",
                        CallContext.LogicalGetData("name")));

                    Thread.Sleep(2000); // Postpone the ws.Dispose() call.
                }

                using (StreamReader sr = new StreamReader(ms, Encoding.UTF8)) {
                    Console.WriteLine("Stream length: {0} bytes", ms.Length);
                    ms.Position = 0;
                    Console.WriteLine("Data: \n{0}", sr.ReadToEnd());
                }
            }

            Console.WriteLine("Hit <Enter> for exit...");
            Console.ReadLine();
        }
    }
}

【问题讨论】:

  • 三个线程没有达到按您将它们排队的顺序产生输出的点这一事实并不意味着它们没有按照您将它们排队的顺序启动。请记住它实际上是机器代码被执行,而不是 C# 代码,所以你的一行代码实际上会导致机器执行许多指令。
  • @jmcilhinney 如果我将许多将一些信息写入流(而不是控制台输出)的小任务放入线程池 qwery 队列中会怎样?在这种情况下,书写顺序对我来说非常重要,否则文档格式会出错。
  • 操作系统不提供任何保证来公平地分配线程之间的处理器时间。即使ThreadPool 将保证工作项将按照它们排队的顺序开始(它不会),你仍然不能保证它们以与开始时相同的顺序完成工作。
  • 如果您需要有序并行处理,则不能使用 QueueUserWorkItem。您应该查看 PLINQ 扩展方法,它是 Ordered() 扩展来完成您的并行工作。
  • 另外,为什么顺序很重要?

标签: c# .net multithreading threadpool


【解决方案1】:

线程池使用队列将“要做的事情”输入并从中取出“要做的事情”。

当添加一个任务时,它将把它放在一个可用的槽中,只要看看 Visual Studio 中的tread窗口,你就会发现它不是一个队列,它是一个固定大小的数组(如果变大可以增长) 参见“JustDecompile”中的图片

如果您的逻辑要求您执行第 1 步然后第 2 步,则您不能使用该方法,“多线程”的本质是您在后台启动某些以某种方式隔离的东西,即“工作声明” ",按设计工作,一旦资源可用就运行任务。

查看该行为时,将为您提供预期流程的是 Task.ContinueWith(action),您可以将操作链接在一起,如图所示 here

【讨论】:

    猜你喜欢
    • 2014-04-02
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多