gpt4 book ai didi

c# - SemaphoreSlim.WaitAsync 延续代码

转载 作者:太空狗 更新时间:2023-10-30 00:51:41 28 4
gpt4 key购买 nike

我对 await 关键字的理解是,await 限定语句之后的代码在完成后作为该语句的延续运行。

因此以下两个版本应该产生相同的输出:

    public static Task Run(SemaphoreSlim sem)
{
TraceThreadCount();
return sem.WaitAsync().ContinueWith(t =>
{
TraceThreadCount();
sem.Release();
});
}

public static async Task RunAsync(SemaphoreSlim sem)
{
TraceThreadCount();
await sem.WaitAsync();
TraceThreadCount();
sem.Release();
}

但他们没有!

完整程序如下:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace CDE
{
class Program
{
static void Main(string[] args)
{
try
{
var sem = new SemaphoreSlim(10);
var task = Run(sem);

Trace("About to wait for Run.");

task.Wait();

Trace("--------------------------------------------------");
task = RunAsync(sem);

Trace("About to wait for RunAsync.");

task.Wait();
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
Trace("Press any key ...");
Console.ReadKey();
}

public static Task Run(SemaphoreSlim sem)
{
TraceThreadCount();
return sem.WaitAsync().ContinueWith(t =>
{
TraceThreadCount();
sem.Release();
});
}

public static async Task RunAsync(SemaphoreSlim sem)
{
TraceThreadCount();
await sem.WaitAsync();
TraceThreadCount();
sem.Release();
}

private static void Trace(string fmt, params object[] args)
{
var str = string.Format(fmt, args);
Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, str);
}
private static void TraceThreadCount()
{
int workerThreads;
int completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Trace("Available thread count: worker = {0}, completion port = {1}", workerThreads, completionPortThreads);
}
}
}

这是输出:

[9] Available thread count: worker = 1023, completion port = 1000
[9] About to wait for Run.
[6] Available thread count: worker = 1021, completion port = 1000
[9] --------------------------------------------------
[9] Available thread count: worker = 1023, completion port = 1000
[9] Available thread count: worker = 1023, completion port = 1000
[9] About to wait for RunAsync.
[9] Press any key ...

我错过了什么?

最佳答案

async-await 针对您正在等待的任务已经完成的时间进行优化(当您将信号量设置为 10 而只有 1 个线程使用它时就是这种情况)。在那种情况下,线程只是同步进行。

您可以看到,通过向 RunAsync 添加一个实际的异步操作并查看它如何改变正在使用的线程池线程(这将是当您的信号量为空并且调用者实际需要异步等待):

public static async Task RunAsync(SemaphoreSlim sem)
{
TraceThreadCount();
await Task.Delay(1000);
await sem.WaitAsync();
TraceThreadCount();
sem.Release();
}

您还可以对 Run 进行此更改,并让它同步执行延续并获得与 RunAsync 相同的结果(线程计数方面):

public static Task Run(SemaphoreSlim sem)
{
TraceThreadCount();
return sem.WaitAsync().ContinueWith(t =>
{
TraceThreadCount();
sem.Release();
}, TaskContinuationOptions.ExecuteSynchronously);
}

输出:

[1] Available thread count: worker = 1023, completion port = 1000  
[1] Available thread count: worker = 1023, completion port = 1000
[1] About to wait for Run.
[1] --------------------------------------------------
[1] Available thread count: worker = 1023, completion port = 1000
[1] Available thread count: worker = 1023, completion port = 1000
[1] About to wait for RunAsync.
[1] Press any key ...

重要说明:当说 async-await 充当延续时,它更像是一个类比。这些概念之间存在几个关键差异,尤其是关于 SynchronizationContextasync-await 自动保留当前上下文(除非您指定 ConfigureAwait(false)),因此您可以在重要的环境(UI、ASP.Net 等)中安全地使用它.).关于同步上下文的更多信息 here .

此外,await Task.Delay(1000); 可以替换为 await Task.Yield();说明时间无关紧要,只是方法异步等待这一事实很重要。 Task.Yield() 在异步代码的单元测试中通常很有用。

关于c# - SemaphoreSlim.WaitAsync 延续代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25654498/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com