使用异步/等待来限制信号量线程 [英] Semaphore thread throttling with async/await

查看:87
本文介绍了使用异步/等待来限制信号量线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到了一个限制异步/等待调用线程的示例.在分析并使用了机器上的代码后,我想到了做相同事情的略有不同的方法.我不确定的是,引擎盖下发生的事情是否几乎相同,或者是否存在任何细微的差异值得关注?

I recently came across an example of throttling threads for async/await calls. After analyzing and playing with the code on my machine, I came up with a slightly different way of doing the same thing. What I'm uncertain about is wether what is happening under the hood is pretty much the same or if there are any subtle differences worth noting?

这是基于原始示例的代码:

Here's the code based on the original example:

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5);

public async Task CallThrottledTasks()
{
    var tasks = new List<Task>();

    for (int count = 1; count <= 20; count++)
    {
        await _semaphore.WaitAsync();

        tasks.Add(Task.Run(async () =>
            {
                try
                {
                    int result = await LongRunningTask();
                    Debug.Print(result.ToString());
                }
                finally
                {
                    _semaphore.Release();
                }
            }));
    }

    await Task.WhenAll(tasks);

    Debug.Print("Finished CallThrottledTasks");
}

这是我对相同代码的看法:

And here's my take on the same code:

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5);

public async Task CallThrottledTasks()
{
    var tasks = new List<Task>();

    for (int count = 1; count <= 20; count++)
    {
        await _semaphore.WaitAsync();

        tasks.Add(LongRunningTask().ContinueWith(t =>
        {
            try
            {
                int result = t.Result;
                Debug.Print(result.ToString());
            }
            finally
            {
                _semaphore.Release();
            }
        }));
    }

    await Task.WhenAll(tasks);

    Debug.Print("Finished CallThrottledTasks");
}

我可能还差得远,但是看来Task.Run方法正在创建一个任务以运行LongRunningTask(),然后添加了一个连续内容以打印结果,而我的方法却绕过了Task.Run创建的任务,并且结果更加精简.这是正确的还是我在这里偏离了基础?

I'm probably way off, but It seems like the Task.Run approach is creating a task to run LongRunningTask() and then adds a continuation to print the result whereas my approach bypasses the task created by Task.Run and is a bit leaner as a result. Is this accurate or am I way off base here?

推荐答案

它没有多少精简之处,只是一点点.通常,我避免在async代码中使用ContinueWith,因为await更干净并且具有更多的async友好默认语义.首先针对开发人员时间进行优化,然后针对其他考虑因素进行优化.

It's not much leaner, just a little bit. Usually, I avoid ContinueWith in async code because await is cleaner and has more async-friendly default semantics. Optimize for developer time first, then optimize for other considerations.

您的代码确实会稍微改变语义:在原始代码中,LongRunningTask是从线程池上下文中执行的,而在您的代码中,它是从CallThrottledTasks上下文中执行的.同样,您的代码也不会干净地传播LongRunningTask中的异常. Task<T>.Result将在AggregateException中包装异常,而await将不进行任何包装.

Your code does change the semantics slightly: in the original code, LongRunningTask was executed from a thread pool context, and in your code it's executed from whatever the CallThrottledTasks context is. Also, your code won't propagate exceptions from LongRunningTask cleanly; Task<T>.Result will wrap exceptions in AggregateException, while await will not do any wrapping.

这篇关于使用异步/等待来限制信号量线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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