Я бы посоветовал вам посмотреть на 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
, чтобы превратить эти лямбда-функции в наблюдаемые функции:
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: