Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我的ThreadID对于并行运行的10个任务不是唯一的?_C#_.net_Multithreading - Fatal编程技术网

C# 为什么我的ThreadID对于并行运行的10个任务不是唯一的?

C# 为什么我的ThreadID对于并行运行的10个任务不是唯一的?,c#,.net,multithreading,C#,.net,Multithreading,我的代码将10个“作业”放入队列,显示它们的线程ID,然后立即并行运行。我知道这些作业是并行运行的,因为每个作业只是20秒的延迟,所有10个作业都在20秒内完成。让我困惑的是,存在多个重复的ThreadID,根据我所读的内容,每个线程应该有一个唯一的ID。这怎么可能?是否存在重复项,因为重复项可能位于不同的处理器内核上(如果是这样的话,这将不太好,因为最终我希望能够使用线程ID取消任务) 下面是显示在我的控制台窗口上的线程ID列表“ 线程ID:10 线程ID:11 线程ID:11 线程ID:12

我的代码将10个“作业”放入队列,显示它们的线程ID,然后立即并行运行。我知道这些作业是并行运行的,因为每个作业只是20秒的延迟,所有10个作业都在20秒内完成。让我困惑的是,存在多个重复的ThreadID,根据我所读的内容,每个线程应该有一个唯一的ID。这怎么可能?是否存在重复项,因为重复项可能位于不同的处理器内核上(如果是这样的话,这将不太好,因为最终我希望能够使用线程ID取消任务)

下面是显示在我的控制台窗口上的线程ID列表“

线程ID:10 线程ID:11 线程ID:11 线程ID:12 线程ID:13 线程ID:14 线程ID:15 线程ID:16 线程ID:6 线程ID:6

我尽可能地简化了代码,并计算了程序完成所需的时间

这是一个控制台应用程序

class Program
{

    private static Object lockObj = new Object();

    static void Main(string[] args)
    {
        var q = new TPLDataflowMultipleHandlers();
        var numbers = Enumerable.Range(1, 10);

        Console.Clear();

        foreach (var num in numbers)
        {
            q.Enqueue(num.ToString());
        }
        Console.ReadLine();
    }
} // end of program class


public class TPLDataflowMultipleHandlers
{
    private static Object lockObj = new Object();

    private ActionBlock<string> _jobs;

    public TPLDataflowMultipleHandlers()
    {
        var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions()
        {
            MaxDegreeOfParallelism = 16,
        };

        _jobs = new ActionBlock<string>(async (job) =>
       {
           ShowThreadInformation("Main Task(Task #" + Task.CurrentId.ToString() + ")");
           Console.WriteLine($"STARTING job:{job},  thread: { Thread.CurrentThread.ManagedThreadId}");

           await Task.Delay(20000);

           Console.WriteLine($"FINISHED job:{job},  thread: { Thread.CurrentThread.ManagedThreadId}");
       }, executionDataflowBlockOptions);
    }

    public void Enqueue(string job)
    {
        _jobs.Post(job);
    }

    private static void ShowThreadInformation(String taskName)
    {
        String msg = null;
        Thread thread = Thread.CurrentThread;
        lock (lockObj)
        {
            msg = String.Format("{0} thread information\n", taskName) +
                  String.Format("   Background: {0}\n", thread.IsBackground) +
                  String.Format("   Thread Pool: {0}\n", thread.IsThreadPoolThread) +
                  String.Format("   Thread ID: {0}\n", thread.ManagedThreadId);
        }
        Console.WriteLine(msg);
    }
}
类程序
{
私有静态对象lockObj=新对象();
静态void Main(字符串[]参数)
{
var q=新的TPLDataFlowMultipleHandler();
变量数=可枚举范围(1,10);
Console.Clear();
foreach(数值形式的变量num)
{
q、 排队(num.ToString());
}
Console.ReadLine();
}
}//程序类结束
公共类TPLDataFlowMultipleHandler
{
私有静态对象lockObj=新对象();
私人行动块(jobs);;
公共TPLDataFlowMultipleHandler()
{
var executionDataflowBlockOptions=新的executionDataflowBlockOptions()
{
MaxDegreeOfParallelism=16,
};
_作业=新操作块(异步(作业)=>
{
ShowThreadInformation(“主任务(任务#“+Task.CurrentId.ToString()+”));
WriteLine($“启动作业:{job},线程:{thread.CurrentThread.ManagedThreadId}”);
等待任务。延迟(20000);
WriteLine($“完成的作业:{job},线程:{thread.CurrentThread.ManagedThreadId}”);
},executionDataflowBlockOptions);
}
公共无效排队(字符串作业)
{
_职位(职位);
}
私有静态void ShowThreadInformation(字符串taskName)
{
字符串msg=null;
Thread Thread=Thread.CurrentThread;
锁(lockObj)
{
msg=String.Format(“{0}线程信息\n”,任务名)+
格式(“背景:{0}\n”,thread.IsBackground)+
Format(“线程池:{0}\n”,Thread.IsThreadPoolThread)+
格式(“线程ID:{0}\n”,Thread.ManagedThreadId);
}
控制台写入线(msg);
}
}

我完全期待10个唯一的线程ID号。

线程和任务不是同一件事-将
线程
视为一个工作者,将
任务
视为一项要执行的工作。仅仅因为你创建了10件需要完成的事情并不意味着你需要10个工作者来完成它们-如果例如,您已经拥有的4个辅助线程(.NET
线程池中的默认辅助线程数)开始执行工作单元,并且只有在现有辅助线程似乎无法跟上时才会创建新的辅助线程(
线程)“您在代码中创建的线程非常短,因此执行速度非常快,执行该线程的同一个线程变为空闲线程,并运行另一个在后台队列中等待的线程

如果您想看到这一点,只需将类似于
Thread.Sleep(30000)
的内容放在
showthreadminformation
中的某个位置即可。这将导致任务的执行人为地过长,.NET线程池将注意到队列中的任务正在耗尽,并启动新线程来执行它们


看看这里-

线程和任务不是同一件事-将
线程
视为工作者,将
任务
视为要执行的工作。仅仅因为你创建了10件需要完成的事情并不意味着你需要10个工人来完成它们——如果你已经有4个工人(在.NET
ThreadPool
中默认的工人线程数量)开始执行工作单元,并且新的工人(
threads
)只有在现有的似乎跟不上的情况下才会创建。您在代码中创建的每个“工作单元”都非常短,因此它执行得非常快,执行它的同一个线程变为空闲线程,并运行另一个在后台队列中等待的线程

如果您想看到这一点,只需将类似于
Thread.Sleep(30000)
的内容放在
showthreadminformation
中的某个位置即可。这将导致任务的执行人为地过长,.NET线程池将注意到队列中的任务正在耗尽,并启动新线程来执行它们


看看这里-

你正在等待20秒的延迟,这意味着你已经放弃了可以在同一线程上运行的其他执行路径。你的示例甚至没有在任何地方调用
showthreadminformation
方法。ActionBlock没有做任何有用的事情,它只启动了16个异步任务。由threadpool调度程序执行,它将活动线程的数量限制为内核的数量。混音不是个好主意。好吧,我不觉得自己很笨吗。这很有道理。我用thread.Sleep(20000)重新运行了上面的程序,得到了20个唯一的线程ID号。@PMF它在以下行之后被调用:_jobs=new ActionBlock(async(job)=>你在等待20秒的延迟,这意味着你已经屈服于可以在同一线程上运行的其他执行路径。你的示例甚至没有调用
ShowThreadInfo