C# 为什么我的ThreadID对于并行运行的10个任务不是唯一的?
我的代码将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 我尽可能地简化了代码,并计算了程序完成所需的时间 这是一个控制台应用程序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
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个工人(在.NETThreadPool
中默认的工人线程数量)开始执行工作单元,并且新的工人(threads
)只有在现有的似乎跟不上的情况下才会创建。您在代码中创建的每个“工作单元”都非常短,因此它执行得非常快,执行它的同一个线程变为空闲线程,并运行另一个在后台队列中等待的线程
如果您想看到这一点,只需将类似于Thread.Sleep(30000)
的内容放在showthreadminformation
中的某个位置即可。这将导致任务的执行人为地过长,.NET线程池将注意到队列中的任务正在耗尽,并启动新线程来执行它们
看看这里-你正在等待20秒的延迟,这意味着你已经放弃了可以在同一线程上运行的其他执行路径。你的示例甚至没有在任何地方调用showthreadminformation
方法。ActionBlock没有做任何有用的事情,它只启动了16个异步任务。由threadpool调度程序执行,它将活动线程的数量限制为内核的数量。混音不是个好主意。好吧,我不觉得自己很笨吗。这很有道理。我用thread.Sleep(20000)重新运行了上面的程序,得到了20个唯一的线程ID号。@PMF它在以下行之后被调用:_jobs=new ActionBlock(async(job)=>你在等待20秒的延迟,这意味着你已经屈服于可以在同一线程上运行的其他执行路径。你的示例甚至没有调用ShowThreadInfo