我有许多命令可以调用soap Web服务(Betfair API)。所有都是经典的异步编程模型类型......
public void DoXXX( <input parameters ...> )
{
XXXRequest Request = new XXXRequest();
// populate Request from input parameters ...
BetfairService.BeginXXX( Request, XXXCallback, State );
}
private void XXXCallback(IAsyncResult Result)
{
XXXResponse Response = BetfairService.EndXXX(Result);
if (Response.ErrorCode == XXXErrorCode.OK)
// store data from Response
else
// deal with error
}
我想执行一组指定的命令,然后在完成所有命令后使用组合的返回数据值进行一些计算。
我可以通过创建一个命令队列来执行此操作,并使每个回调方法在完成后触发队列中的下一个命令,并将计算作为队列中的最后一项。然而,这相对较慢。
我理想的解决方案是让所有这些命令并行运行,然后在完成所有命令后触发计算。我已经尝试过查看Task.Factory.FromAsync(),但我找到的所有示例都只包括对BeginXXX / EndXXX的直接调用,而没有对响应做任何事情。
有没有人有任何针对此问题的合适解决方案?
答案 0 :(得分:2)
要使用FromAsync
,您需要指定返回类型:
var task = Task<XXXResponse>.Factory.FromAsync( ...
然后,您的任务的Result
属性为XXXResponse
。
然后,您可以使用Parallel.Invoke
并行运行初始命令。这将阻止所有这些任务完成。然后你可以进行“额外处理”。
或者您可以将初始任务存储在数组中,并使用Task.Factory.ContinueWhenAll
创建延续。
尼克
答案 1 :(得分:1)
我建议您查看Microsoft的Reactive Extensions(Rx)来执行您想要的操作。它允许您将异步操作(以及其他内容)转换为可观察的LINQ查询。
假设我有这三个函数,每个函数都需要花费大量时间来计算:
Func<int> fa = () =>
{
Thread.Sleep(2000);
return 42;
};
Func<int, string, string> fb = (n, t) =>
{
Thread.Sleep(n * 1000);
return t + n.ToString();
};
Func<DateTimeOffset> fc = () =>
{
Thread.Sleep(1000);
return DateTimeOffset.UtcNow;
};
然后我可以使用FromAsyncPattern
方法将这些lambda函数转换为可观察的函数:
Func<IObservable<int>> ofa =
Observable
.FromAsyncPattern<int>(
fa.BeginInvoke,
fa.EndInvoke);
Func<int, string, IObservable<string>> ofb =
Observable
.FromAsyncPattern<int, string, string>(
fb.BeginInvoke,
fb.EndInvoke);
Func<IObservable<DateTimeOffset>> ofc =
Observable
.FromAsyncPattern<DateTimeOffset>(
fc.BeginInvoke,
fc.EndInvoke);
现在我可以通过这样做来启动所有调用:
IObservable<int> oa = ofa();
IObservable<string> ob = ofb(1, "foo");
IObservable<DateTimeOffset> oc = ofc();
有效地并行开始三次计算。现在我们只需将结果汇总在一起。
这就是LINQ的用武之地:
var query =
from a in oa
from b in ob
from c in oc
select new { a, b, c };
然后我订阅此查询以获得结果:
query.Subscribe(p =>
{
Console.WriteLine(p.a);
Console.WriteLine(p.b);
Console.WriteLine(p.c);
});
在我的测试中,我将计时器放在这个代码周围来计算实际执行时间。即使串联运行总时间应为4秒,此代码也会以2结束 - 三者中的任何一个的最长时间。
现在这个例子只是Rx可以做的一点方面,但它是一个很好的起点。
如果我能进一步解释,请大声说出来。
以下是Rx的链接:
答案 2 :(得分:0)
您应该拥有已执行服务调用的计数器。在每个回调方法中,您应该检查此计数器 - 如果它等于服务调用的最大数量,您应该进行额外的处理,否则 - 您只需增加计数器。