SemaphoreSlim.WaitAsync延续code [英] SemaphoreSlim.WaitAsync continuation code

查看:353
本文介绍了SemaphoreSlim.WaitAsync延续code的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的计谋的理解关键字是,code以下的await 合格声明正在运行的该声明的延续,一旦它是完整的。

My understanding of the await keyword was that the code following the await qualified statement is running as the continuation of that statement once it is complete.

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

Hence the following two versions should produce the same output:

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

但他们不这样做!

But they do not!

下面是完整的程序:

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 ...

我在想什么?

What am I missing?

推荐答案

异步等待优化当你等待的任务已经完成了(这是当你有一个情况下,信号量设置为10,只有1个线程使用它)。在这种情况下,该线程刚刚进行同步

async-await optimizes for when the task you're awaiting on has already completed (which is the case when you have a semaphore set to 10 with only 1 thread using it). In that case the thread just carries on synchronously.

您可以看到,通过增加一个实际的异步操作 RunAsync 键,看看它是如何改变线程池中的线程被使用(这将是行为,当你的信号是空的并且调用者实际需要的的异步):

You can see that by adding an actual asynchronous operation to RunAsync and see how it changes the thread pool threads being used (which would be the behavior when your semaphore is empty and the caller actually needs to wait asynchronously):

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

您也可以进行此更改为运行并让它执行继续同步,并得到了相同的结果你的 RunAsync (线数睿智):

You can also make this change to Run and have it execute the continuation synchronously and get the same results as in your RunAsync (thread count wise):

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 ...  


重要提示:当它说,异步等待作为连接它更多的比喻。有这些概念之间有几个关键的不同,特别是关于的SynchronizationContext 秒。 异步等待自动将preserves目前的情况下(除非您指定 ConfigureAwait(假)),所以你可以使用它在安全环境中的事项(UI,ASP.Net,等)。更多关于同步上下文这里


Important Note: When it's said that async-await acts as a continuation it's more of an analogy. There are several critical difference between these concepts, especially regarding SynchronizationContexts. async-await automagically preserves the current context (unless you specify ConfigureAwait(false)) so you can use it safely in environments where that matters (UI, ASP.Net, etc.). More about synchronization contexts here.

这篇关于SemaphoreSlim.WaitAsync延续code的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆