Могу ли я предложить вам рассмотреть Reactive Extensions (Rx) как альтернативный способ использования многопоточности в Silverlight?
Вот ваш код, выполненный в Rx:
Func<int, int, int> calculation = (n1, n2) =>
{
var r = n1 + n2;
r *= r;
r *= 2;
return r;
};
var query =
from callid in Observable.Range(0, 6, Scheduler.ThreadPool)
let n1 = rand.Next(10)
let n2 = rand.Next(10)
from result in Observable.Start(() => calculation(n1, n2))
select new { callid, n1, n2, result };
query.Subscribe(x => { /* do something with result */ });
Он автоматически переносит вычисления в пул потоков - я помещаю параметр Scheduler.ThreadPool
, но это значение по умолчанию для запроса SelectMany
.
С таким кодом вы обычно не беспокоитесьвсе MRE и очень легко читаемый код, который может быть более легко протестирован.
Rx является поддерживаемым продуктом Microsoft и работает как на CLR для настольных ПК, так и на Silverlight.
ссылки для Rx:
О, и я думаю, что причина того, что вы получаете очень разные результаты производительности, заключается в том, что Silverlight имеет только миллисекундное разрешение для синхронизации, поэтому вам действительно придется выполнять вычисления тысячи раз, чтобы получить хорошее среднее значение.
EDIT : в соответствии с запросом в комментариях приведен пример объединения результатов каждого промежуточного вычисления с использованием Rx.
Func<int, int, int> fn1 = (n1, n2) => n1 + n2;
Func<int, int> fn2 = n => n * n;
Func<int, int> fn3 = n => 2 * n;
var query =
from callid in Observable.Range(0, 6, Scheduler.ThreadPool)
let n1 = rand.Next(10)
let n2 = rand.Next(10)
from r1 in Observable.Start(() => fn1(n1, n2))
from r2 in Observable.Start(() => fn2(r1))
from r3 in Observable.Start(() => fn3(r2))
select new { callid, n1, n2, r1, r2, r3 };
Конечно, три лямбда-функциивместо этого можно легко использовать обычные функции методов.
Еще одна альтернатива, если у вас есть функции, использующие асинхронный шаблон BeginInvoke
/ EndInvoke
, - использовать метод расширения FromAsyncPattern
, подобный следующему:
Func<int, int, IObservable<int>> ofn1 =
Observable.FromAsyncPattern<int, int, int>
(fn1.BeginInvoke, fn1.EndInvoke);
Func<int, IObservable<int>> ofn2 =
Observable.FromAsyncPattern<int, int>
(fn2.BeginInvoke, fn2.EndInvoke);
Func<int, IObservable<int>> ofn3 =
Observable.FromAsyncPattern<int, int>
(fn3.BeginInvoke, fn3.EndInvoke);
var query =
from callid in Observable.Range(0, 6, Scheduler.ThreadPool)
let n1 = rand.Next(10)
let n2 = rand.Next(10)
from r1 in ofn1(n1, n2)
from r2 in ofn2(r1)
from r3 in ofn3(r2)
select new { callid, n1, n2, r1, r2, r3 };
Немного беспорядочно, но запрос немного проще.
Примечание: параметр Scheduler.ThreadPool
снова не нужен, но он просто включен, чтобы явно показать, что запрос выполняется с использованием потока.-Бассейн.