是否可以在不同线程上等待任务完成?

Is it possible to await task completion on different threads?

我的意思是,假设我们有一个异步方法 Task<string> CalculateSha256(string s)。来自线程 #1 和线程 #2 的调用是否有可能 连续执行 而不是并发执行,而线程 #1 和 #2 彼此一无所知?比如我有一个控制器,

public async Task<string> Get(string value)
{
    return await CalculateSha256(value);
}

我想要两个不同的请求来连续访问负责计算的代码块 (CalculateSha256)。

您需要同步访问 CalculateSha256 方法,一次只有一个线程执行它。
由于 lock 语句 does not play nicely with async you can use SemaphoreSlim class.

只需将其作为静态字段添加到您的控制器即可:

private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);

并在您的操作中使用 WaitAsync 方法(并且不要忘记在完成时释放它,使用 finally 块):

public async Task<string> Get(string value)
{
    await _semaphoreSlim.WaitAsync();
    try
    {
        return await CalculateSha256(value);
    }
    finally
    { 
        _semaphoreSlim.Release();
    }
}

如果您发现这种方法有用并且您不喜欢重复 try finally 块,您可以创建一个带有受保护的通用助手的基本控制器 class:

protected async Task<T> GetConsecutively(Func<Task<T>> taskFactory)
{
    await _semaphoreSlim.WaitAsync();
    try
    {
        return await taskFactory();
    }
    finally
    { 
        _semaphoreSlim.Release();
    }
}

并修改 Get 方法以将 lambda 表达式传递给它:

public async Task<string> Get(string value)
{
    return await GetConsecutively(() => CalculateSha256(value));
}

或者使用 Stephen Cleary 的 AsyncLock 而不是 SemaphoreSlim,后者支持更接近 lock 语句的高级 API:

private static readonly AsyncLock _asyncLock = new AsyncLock();

public async Task<string> Get(string value)
{
    //Notice the use of using block
    //instead of try and finally 
    using(await _asyncLock.LockAsync())
    {
        return await CalculateSha256(value);
    }
}