如何对等待第一次调用结果的异步方法进行不同的调用?

时间:2017-01-17 21:08:55

标签: c# asynchronous

我们说我有一个从服务器获取数据的方法

Task<Result> GetDataFromServerAsync(...)

如果正在进行的通话正在进行中,我不想向服务器发送新请求,而是等待原始设备完成。

我们说我有

var result = await objet.GetDataFromServerAsync(...);

并且在另一个地方,几乎同时呼叫我有第二次呼叫

var result2 = await objet.GetDataFromServerAsync(...);

如果第一个没有完成,我不希望第二个向服务器发起新请求。我希望两个电话在第一次通话完成后立即获得相同的结果。这是一个概念证明,我有选择,但我想看看这样做有多容易。

2 个答案:

答案 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