C# 为什么线程池可以以相同的优先级启动我的任务,而不是以我发布它们的相同顺序启动它们?

C# 为什么线程池可以以相同的优先级启动我的任务,而不是以我发布它们的相同顺序启动它们?,c#,.net,multithreading,threadpool,C#,.net,Multithreading,Threadpool,我始终通过线程池运行三个操作。他们有同样的优先权。然而,它们的执行顺序并不总是我运行它们的顺序。为什么会这样 我希望线程池将按照我将任务发布到线程池查询队列中的相同顺序启动任务(如果它们具有相同的优先级) 使用系统; 使用System.Runtime.Remoting.Messaging; 使用系统线程; 命名空间线程学习{ 福班{ 公共字符串名称{get;set;} 公共重写字符串ToString(){ 返回名称; } } 班级计划{ 私有静态void Main(字符串[]args){ Con

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

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

使用系统;
使用System.Runtime.Remoting.Messaging;
使用系统线程;
命名空间线程学习{
福班{
公共字符串名称{get;set;}
公共重写字符串ToString(){
返回名称;
}
}
班级计划{
私有静态void Main(字符串[]args){
Console.WriteLine(“主要方法工作…”);
Foo-Foo=newfoo{Name=“Bob”};
CallContext.LogicalSetData(“名称”,foo);
ThreadPool.QueueUserWorkItem(状态=>Console.WriteLine(“1:Name={0}”),
CallContext.LogicalGetData(“名称”);
ExecutionContext.SuppressFlow();
ThreadPool.QueueUserWorkItem(状态=>Console.WriteLine(“2:Name={0}”),
CallContext.LogicalGetData(“名称”);
ExecutionContext.RestoreFlow();
ThreadPool.QueueUserWorkItem(状态=>Console.WriteLine(“3:Name={0}”),
CallContext.LogicalGetData(“名称”);
控制台。WriteLine(“点击退出…”);
Console.ReadLine();
}
}
}
输出可以是:

Main method works...
Hit <Enter> for exit...
2: Name =
1: Name = Bob
3: Name = Bob
Main方法有效。。。
点击退出。。。
2:姓名=
1:Name=Bob
3:Name=Bob

Main方法有效。。。
1:Name=Bob
2:姓名=
3:Name=Bob
点击退出。。。
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();
        }
    }
}
使用系统;
使用System.IO;
使用System.Runtime.Remoting.Messaging;
使用系统文本;
使用系统线程;
命名空间线程学习{
福班{
公共字符串名称{get;set;}
公共重写字符串ToString(){
返回名称;
}
}
班级计划{
私有静态void Main(字符串[]args){
使用(MemoryStream ms=new MemoryStream()){
使用(StreamWriter sw=新StreamWriter(ms,Encoding.UTF8,0x1000,true)){
sw.WriteLine(“主要方法工作…”);
Foo-Foo=newfoo{Name=“Bob”};
CallContext.LogicalSetData(“名称”,foo);
ThreadPool.QueueUserWorkItem(状态=>sw.WriteLine(“1:Name={0}”),
CallContext.LogicalGetData(“名称”);
ExecutionContext.SuppressFlow();
ThreadPool.QueueUserWorkItem(状态=>sw.WriteLine(“2:Name={0}”),
CallContext.LogicalGetData(“名称”);
ExecutionContext.RestoreFlow();
ThreadPool.QueueUserWorkItem(状态=>sw.WriteLine(“3:Name={0}”),
CallContext.LogicalGetData(“名称”);
Thread.Sleep(2000);//推迟ws.Dispose()调用。
}
使用(StreamReader sr=新的StreamReader(ms,Encoding.UTF8)){
WriteLine(“流长度:{0}字节”,ms.length);
ms.Position=0;
WriteLine(“数据:\n{0}”,sr.ReadToEnd());
}
}
控制台。WriteLine(“点击退出…”);
Console.ReadLine();
}
}
}

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

当添加一个任务时,它会将其放置在一个可用的插槽中,只需查看Visual Studio中的tread窗口,您就会发现它不是一个队列,而是一个固定大小的数组(如果变得更大,则可以增长)请参阅“JustDecompile”中的图像

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


在查看该行为时,可以得到预期流的是,您可以将操作链接在一起,如图所示。

三个线程没有达到按您对它们进行排队的顺序生成输出的点,这并不意味着它们没有按您对它们进行排队的顺序启动。请记住,实际上执行的是机器代码,而不是C#代码,因此一行代码实际上会导致机器执行大量指令。@jmchiliney如果我将许多小任务放入线程池qwery队列,将一些信息写入流中(而不是控制台输出),会怎么样?在这种情况下,写入顺序对我来说非常重要,否则文档格式会出错。操作系统不能保证在线程之间公平分配处理器时间。即使
ThreadPool
将保证工作项将以其排队时的相同顺序启动(事实并非如此),您仍然无法保证它们以其启动时的相同顺序完成工作。如果需要有序并行处理,则不能使用QueueUserWorkItem。你应该看看PLINQ扩展方法,它是
Ordered()
extension来完成你的并行工作。还有,为什么顺序是什么很重要?
Main method works...
1: Name = Bob
2: Name =
3: Name = Bob
Hit <Enter> for exit...
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();
        }
    }
}