如何最快地获得第一个异步响应(并且不执行剩余的响应)?

时间:2017-04-13 15:27:13

标签: c# wcf async-await system.reactive observable

以下是设置:有一个联邦远程服务可以返回特定值是正确还是不正确。我们可以根据需要发送请求,每个请求最多可以发送50个远程服务。

由于我们只需要使用正确的值,并且可能值的集合很小(~700),我们只能发送15个左右的50个批处理请求,正确的值将成为结果集的一部分。因此,我使用了以下代码:

Observable
    .Range(0, requests.Count)
    .Select(i => Observable.FromAsync(async () =>
    {
        responses.Add(await client.FederalService.VerifyAsync(requests[i]));
        Console.Write(".");
    }))
    .Merge(8)
    .Wait();

但是 - 我不喜欢的是,如果之前的一个请求具有正确的值,我仍然会通过服务浪费时间运行所有可能性。我试图让这次运行尽可能快。我知道退出条件(响应代码从1到99,50-59内的任何响应代码表示该值是“正确的”)。

有没有办法让这段代码更聪明,所以我们最小化请求数量?不幸的是,我们验证的值是均匀分布的,因此排序请求什么都不做(我知道)。

2 个答案:

答案 0 :(得分:3)

您应该考虑使用FirstAsync method here

  

我们示例中的秘密是FirstAsync方法。我们实际上在等待观察者返回的第一个结果不关心任何进一步的结果

所以你的代码可能是这样的:

await Observable
    .Range(0, requests.Count)
    .Select(i => Observable.FromAsync(async () =>
    {
        responses.Add(await client.FederalService.VerifyAsync(requests[i]));
        Console.Write(".");
    }))
    .FirstAsync()
    .Subscribe(Console.WriteLine);

> System.Reactive.Linq.ObservableImpl.Defer`1[System.Reactive.Unit]

Rx and Await: Some Notes文章提供了类似方法的一些技巧。例如,您有FirstAsync的重载,可以过滤,LINQ'方法First

await Observable
    .Range(0, requests.Count)
    .Select(i => Observable.FromAsync(async () =>
    {
        responses.Add(await client.FederalService.VerifyAsync(requests[i]));
        Console.Write(".");
    }))
    .FirstAsync(r => /* do the check here */)
    .Subscribe(Console.WriteLine);

答案 1 :(得分:1)

你非常接近。将您的观察结果更改为:

Observable
    .Range(0, requests.Count)
    .Select(i => Observable.FromAsync(async () =>
    {
        var response = await Task.FromResult(i); //replace with client.FederalService.VerifyAsync(requests[i])
        responses.Add(response);
        Console.Write($"{i}.");
        var responseCode = response; //replace with however you get the response code.
        return responseCode >= 50 && responseCode <= 59;
    }))
    .Merge(8)
    .Where(b => b)
    .Take(1)
    .Wait();

这样你的observable继续发出值,所以你可以继续对它进行操作。