我的意思是说,我们有一个异步方法Task<string> CalculateSha256(string s)
。是否有可能,来自线程#1和线程#2的调用被执行连续,因为它们被选择同时执行,没有线程#1和#2知道彼此之间的任何事情?例如,我有一个控制器,
public async Task<string> Get(string value)
{
return await CalculateSha256(value);
}
我想要两个不同的请求来连续访问负责计算的代码块(CalculateSha256)。
答案 0 :(得分:4)
您需要同步对CalculateSha256方法的访问,一次只有一个线程会执行它。
自lock
语句does not play nicely with async起,您就可以使用SemaphoreSlim
类。
只需将其作为静态字段添加到控制器:
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块,则可以使用受保护的通用帮助程序创建基本控制器类:
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);
}
}