简体   繁体   English

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

[英]Why are my ThreadIDs not unique for 10 tasks running in parallel?

My code puts 10 'jobs' in a queue, displays their thread IDs, and start running right away and in parallel.我的代码将 10 个“作业”放入队列中,显示它们的线程 ID,然后立即开始并行运行。 I know the jobs are running in parallel since each job is simply a 20 second delay, and all 10 jobs complete in 20 seconds.我知道这些作业是并行运行的,因为每个作业只是延迟 20 秒,而所有 10 个作业在 20 秒内完成。 What perplexes me is that there are several duplicate ThreadIDs, and supposedly each thread should have a unique ID from what I have read.让我感到困惑的是,有几个重复的 ThreadID,并且据说每个线程都应该有一个我读过的唯一 ID。 How is this possible?这怎么可能? Are there duplicates because the duplicates could be on different processor cores (if so this would not be great as eventually I want to be able to cancel a task using its thread ID)?是否存在重复项,因为重复项可能位于不同的处理器内核上(如果是这样,这将不是很好,因为最终我希望能够使用其线程 ID 取消任务)?

Here's a list of the thread IDs that were shown on my console window"这是在我的控制台窗口上显示的线程 ID 列表”

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

I simplified the code as much as I could, and timed how long it took the program to finish.我尽可能地简化了代码,并计算了程序完成所需的时间。

This is a console app这是一个控制台应用程序

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);
    }
}

I was fully expecting 10 unique thread ID numbers.我完全期待 10 个唯一的线程 ID 号。

Threads and Tasks are not the same things - think of a Thread as a worker, and a Task as a piece of work to be performed.线程和任务不是一回事——将Thread视为工作人员,将Task视为要执行的工作。 Just because you created 10 things that need to be done doesn't mean that you need 10 workers to do them - it would be much more efficient if, say, the 4 workers you already have (the default amount of worker threads in the .NET ThreadPool ) started executing the work units, and new workers ( Threads ) would be created only if the existing ones don't seem to keep up.仅仅因为您创建了 10 件需要完成的事情并不意味着您需要 10 个工作人员来完成它们 - 例如,如果您已经拥有 4 个工作人员(.NET 中的默认工作线程数量),效率会更高ThreadPool ) 开始执行工作单元,并且只有在现有工作单元似乎跟不上时才会创建新工作单元 ( Threads )。 Each "work unit" you created in your code is very short, and so it gets executed very quickly and the same thread that performed it becomes free and runs another one that was waiting in a queue in the background.您在代码中创建的每个“工作单元”都很短,因此它执行得非常快,执行它的同一线程变得空闲并运行另一个在后台队列中等待的线程。

If you want to see this in action, just place something like Thread.Sleep(30000) somewhere in your ShowThreadInformation .如果您想看到它的实际效果,只需在ShowThreadInformation中的某处放置类似Thread.Sleep(30000)的东西。 This will cause the execution of your tasks to be artificially long, and the .NET thread pool will notice tasks are being starved in the queue and spin up new threads to execute them.这将导致您的任务的执行被人为地延长,并且 .NET 线程池将注意到任务在队列中被饿死并启动新线程来执行它们。

Take a look here - What is the difference between task and thread?看看这里 - 任务和线程有什么区别?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM