我们说我有一个从服务器获取数据的方法
Task<Result> GetDataFromServerAsync(...)
如果正在进行的通话正在进行中,我不想向服务器发送新请求,而是等待原始设备完成。
我们说我有
var result = await objet.GetDataFromServerAsync(...);
并且在另一个地方,几乎同时呼叫我有第二次呼叫
var result2 = await objet.GetDataFromServerAsync(...);
如果第一个没有完成,我不希望第二个向服务器发起新请求。我希望两个电话在第一次通话完成后立即获得相同的结果。这是一个概念证明,我有选择,但我想看看这样做有多容易。
答案 0 :(得分:3)
以下是使用Lazy<Task<T>>
的简短示例:
var lazyGetDataFromServer = new Lazy<Task<Result>>
(() => objet.GetDataFromServerAsync(...));
var result = await lazyGetDataFromServer.Value;
var result2 = await lazyGetDataFromServer.Value;
这两个await
是否是从单独的线程完成并不重要,因为Lazy<T>
是线程安全的,所以如果第二次运行result2
仍将等待并使用相同的输出来自result
。
使用code from here,您可以将其包含在名为AsyncLazy<T>
的类中,并添加自定义GetAwaiter
,这样您就可以await
而无需执行此操作.Value
,非常整洁=)
答案 1 :(得分:0)
您可以在方法中使用任何内容进行同步。
例如,我使用了gem install metasploit-payloads -v '1.2.6'
:
SemaphoreSlim
用法:
public class PartyMaker
{
private bool _isProcessing;
private readonly SemaphoreSlim _slowStuffSemaphore = new SemaphoreSlim(1, 1);
private DateTime _something;
public async Task<DateTime> ShakeItAsync()
{
try
{
var needNewRequest = !_isProcessing;
await _slowStuffSemaphore.WaitAsync().ConfigureAwait(false);
if (!needNewRequest) return _something;
_isProcessing = true;
_something = await ShakeItSlowlyAsync().ConfigureAwait(false);
return _something;
}
finally
{
_isProcessing = false;
_slowStuffSemaphore.Release();
}
}
private async Task<DateTime> ShakeItSlowlyAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
return DateTime.UtcNow;
}
}
结果如下:
var maker = new PartyMaker();
var tasks = new[] {maker.ShakeItAsync(), maker.ShakeItAsync()};
Task.WaitAll(tasks);
foreach (var task in tasks)
{
Console.WriteLine(task.Result);
}
Console.WriteLine(maker.ShakeItAsync().Result);
<强> UPD 强> 通过此修改,您可以使用args调用异步方法:
17.01.2017 22:28:39
17.01.2017 22:28:39
17.01.2017 22:28:41