.NET Framework如何分配线程ID?

时间:2018-05-25 15:51:11

标签: c# .net multithreading visual-studio async-await

我的问题与this question有关。该问题中的代码在循环内生成多个线程,并且OP在那里观察到其日志记录中的线程ID似乎随着时间的推移而不断增加。那个问题是关于Java的,但它让我思考:JVM和.NET Framework如何首先分配线程ID?我特别感兴趣的是OP在他的帖子中描述的情况(用于验证线程实际上是按预期创建和销毁的)以及有关如何解释Visual Studio诊断工具日志的更多上下文。我也对自己对框架如何运作的理解感兴趣。

我在这里主要讨论.NET Framework,因为它可能过于宽泛而不能同时询问这两个问题(虽然我也非常高兴听到有关JVM的详细信息)。但是,这是我在Visual Studio诊断工具的“事件”选项卡中获取的日志示例:

程序输出:线程0x44c已退出,代码为0(0x0)。

以下是一些线程ID:

0xcb0
0x2c4c
0x2c5c
0x1b10
0x1a60
0x27b4
0x2b80
0x2e04

那些看起来不是特别顺序的。该日志本身并不具备非常丰富的信息,例如,无需从Visual Studio中的“线程”窗口获取更多上下文,因此我希望更多地了解如何在第一个中分配这些内容。这个地方将为这些活动提供更多背景信息。

以下是我使用的代码示例:

await jobs.AsyncForEach(async delegate (Job job)
    {
       // Do some stuff, some of which involves async/await HttpClient calls to a RESTful API
    }, GlobalSettings.maxDegreeOfParallelism);

jobs的类型为List<Job>GlobalSettings.maxDegreeOfParallelismconst int,指定最大并行度(由于我们的供应商的API限制),以及{{1 }}是AsyncForEach上的扩展方法:

IEnumerable<T>

目前可以在以下三种环境之一中运行:WPF应用程序,控制台应用程序或单元测试。我在这里展示的日志来自单元测试运行,但控制台应用程序日志似乎非常相似。

我确实认识到public static async Task AsyncForEach<T>(this IEnumerable<T> enumerable, Func<T, Task> action, int degreeOfParallelism) { List<Task> tasks = new List<Task>(); foreach (T item in enumerable) { if (tasks.Count >= degreeOfParallelism) { await Task.WhenAny(tasks); tasks = tasks.Where(t => !t.IsCompleted).ToList(); } Task actionTask = action(item); tasks.Add(actionTask); } await Task.WhenAll(tasks); } / async在这种情况下的工作方式有所不同,并且如果有&#39,则没有明确保证异步代码将在哪个线程上运行。 ;没有同步上下文;但是,对于它的价值,我并未在此代码中的任何位置使用awaitnew ThreadThreadPool.QueueUserWorkItem向其自己的线程明确指定任何代码

当我在Google上搜索此内容时,我看到了有关托管线程ID与如何从线程获取ID之间差异的文档。但是,这些并没有真正回答.NET Framework首先提出的问题。

我也很清楚Visual Studio Threads窗口,它显示了ID,关联进程,托管ID,类别,名称和线程位置。这也没有完全回答框架如何指定那些开头的问题。

1 个答案:

答案 0 :(得分:4)

它没有。

有两个不同的实体: native 线程(由操作系统创建)和托管线程(由CLR创建)。线程ID来自操作系统,ManagedThreadID来自CLR。两者都是计数器,通过OS在CLR启动时具有更大的线程对象池。线程ID在每个操作系统中都是唯一的,CLR线程对于每个进程都是唯一的。

托管线程本质上是一种数据结构,存储在本机线程的TLS内存部分,CLR可以编辑它,因此允许托管线程从一个本地线程切换到另一个本地线程。通过光纤API在一个本机线程上托管多个托管线程。您可以使用Thread.BeginThreadAffinity将托管线程粘贴到同一本机线程。此外,桌面应用程序必须让其主要托管线程映射到相同的本机线程(操作系统将重绘,键盘事件和多个其他内容的消息发送到特定本机线程的消息循环,CLR选择它)因此,那些应用程序中的主线程需要具有单线程公寓模型,以确保它。