简体   繁体   English

在转移到与调用方相同的线程之前(对于UI应用程序),是否在内部创建另一个线程

[英]Does await create another thread internally before shifting to the same thread as the caller (for UI application)

What I know about async/await is that when the task completes, the continuation is run on the same context when the await was called, which would, in my case, be the UI thread. 我对async / await的了解是,当任务完成时,继续在调用await的同一上下文中运行,就我而言,这就是UI线程。 But my question is, does it create a new thread (internally) after IO is complete and before moving to the same UI thread. 但是我的问题是,它会在IO完成之后并移至相同的UI线程之前(内部)创建一个新线程。

I am sharing a piece of code. 我正在共享一段代码。 If I click on this button once, It shows that available thread is 1023 before executing await, but after that, available threads dropped to 1022. Although When I check the thread id, it is the same as UI thread. 如果单击一次此按钮,则表明执行等待之前可用线程为1023,但此后,可用线程降至1022。尽管当我检查线程ID时,它与UI线程相同。

    private async void button1_ClickAsync(object sender, EventArgs e)
    {
        int x, y;
        ThreadPool.GetAvailableThreads(out x, out y);
        textBox1.Text = x.ToString()+"..."+y.ToString();
        await Task.Delay(5000);
        ThreadPool.GetAvailableThreads(out x, out y);
        textBox1.Text = x.ToString() + "..." + y.ToString();
    }

But interestingly, next time when I click on this button, number of available threads remains 1023 (before and after await). 但是有趣的是,下次我单击该按钮时,可用线程数仍为1023(在等待之前和之后)。

But my question is, does it create a new thread (internally) after IO is complete and before moving to the same UI thread. 但是我的问题是,它会在IO完成之后并移至相同的UI线程之前(内部)创建一个新线程。

Other threads may be temporarily used, but you don't need to worry about that. 可能会暂时使用其他线程,但是您不必为此担心。

In particular, I/O on .NET generally goes through an I/O completion port that is part of the thread pool. 特别是,.NET上的I / O通常通过作为线程池一部分的I / O完成端口。 I/O threads are automatically added and removed as necessary. I / O线程会根据需要自动添加和删除。 Fairly often, the I/O has some additional work to do before it actually is ready to return to your code (eg, parsing HTTP response headers), so a lot of the BCL I/O code will actually use the I/O thread just to queue work to the thread pool. 通常,在I / O实际准备好返回到代码之前(例如,解析HTTP响应标头),还有很多其他工作要做,因此许多 BCL I / O代码实际上将使用I / O线程只是将工作排队到线程池中。 So a thread pool worker thread is often used (briefly) by I/O code. 因此,I / O代码经常(简短地)使用线程池工作线程。

Also, in this particular example, I believe there's a separate timer thread as well, that coalesces system timers. 另外,在这个特定的示例中,我相信还有一个单独的计时器线程可以合并系统计时器。 Naturally, this is an implementation detail and subject to change. 自然,这是一个实现细节,并且随时可能更改。

So, in summary, other threads may be created/destroyed/temporarily used, but you don't have to worry about it. 因此,总而言之,可能会创建/销毁/临时使用其他线程,但是您不必为此担心。 They're all managed by the BCL or .NET runtime in a very efficient manner, striking a balance between reusing threads (minimizing churn) and minimizing resource use (especially memory). 它们全部由BCL或.NET运行时以非常有效的方式进行管理,从而在重用线程(最小化搅动)和最小化资源使用(尤其是内存)之间取得平衡。

I am guessing you meant it dropped to 1022. 我猜你的意思是下降到1022。

In general I think it depends on the async call being made. 一般来说,我认为这取决于进行的异步调用。 Disk and network calls will come back on a thread from the I/O completion thread pool. 磁盘和网络调用将从I / O完成线程池中的线程返回。 It appears that Task.Delay returns on a regular worker thread. 看来Task.Delay在常规工作线程上返回。

You can change the line to await Task.Delay(5000).ConfigureAwait(false); 您可以将行更改为await Task.Delay(5000).ConfigureAwait(false); , set a breakpoint after it and check the Threads window to see this directly. ,在其后设置一个断点,并检查“线程”窗口以直接查看此断点。

It will complete on a worker thread no matter where you call it from. 无论您从哪里调用它,它都将在工作线程上完成。 await doesn't communicate the calling context to the function implementing the async operation; await不会将调用上下文传递给实现异步操作的函数; it only adds the extra step of returning to the UI thread when it's done. 完成后,它仅添加返回UI线程的额外步骤。

I wouldn't read too much into tracking the exact number here; 在这里跟踪确切的数字我不会读太多。 the CLR has its own algorithms that manage the thread pool size and those can change from release to release. CLR具有自己的算法来管理线程池大小,并且这些算法可以随版本的不同而变化。 And I wouldn't stress about it using a different thread there: in a normal app it will simply re-use an existing thread from the pool and the operation will be very fast. 而且我不会在那使用其他线程来强调它:在普通应用程序中,它将仅重用池中的现有线程,并且操作将非常快。

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

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