2009-11-21 3 views
0
var arguments = new double[] { 1d, 2d, 3d }; 
var result = arguments.Select(arg => Math.Sqrt(arg)); 

Теперь представьте асинхронный метод вместо Math.Sqrt (я не уверен, что ниже метод является истинным async метод, но он ведет себя примерно как один)Как синхронизировать асинхронные методы?

public void BeginSqrt(Action<double> callback, double argument) 
{ 
    Thread.Sleep(100); 
    callback(Math.Sqrt(argument)); 
} 

Там нет правильного способа вызова таких метод без разделения кода. Итак, давайте синхроним этот асинхронный метод с AutoResetEvent. Я создал вспомогательный класс:

public class Synchronizer<T, TResult> 
{ 
    AutoResetEvent _autoResetEvent = new AutoResetEvent(false); 
    TResult _result; 

    public TResult Execute(Action<Action<TResult>,T> beginMethod, T argument) 
    { 
     beginMethod(Callback, argument); 
     _autoResetEvent.WaitOne(); 
     return _result; 
    } 

    void Callback(TResult result) 
    { 
     _result = result; 
     _autoResetEvent.Set(); 
    } 
} 

С помощью этого класса мы можем:

var synchronizer = new Synchronizer<double, double>(); 
var result = arguments.Select(arg => synchronizer.Execute(BeginSqrt, arg)); 

Это решение, которое я создал в течение нескольких минут, пока я думал об этой проблеме. Есть альтернатива этому? Я уверен, что у моих решений есть ошибки, так как он пропускает некоторые блокировки. Для этого существует более проверенная библиотека?

+0

Если я правильно прочитал ваш код, 'BeginSqrt' не делает ничего асинхронно вообще. Он просто передает возвращаемое значение обратному вызову вместо его возврата («стиль продолжения прохождения»). Ваш «Синхронизатор» в основном представляет собой оболочку, которая возвращает «BeginSqrt» обратно в обычный метод. Нет параллелизма, поэтому никаких блокировок не требуется. – dtb

+0

@dtb Вы правы, может быть, я должен изменить его на настоящий асинхронный метод для разъяснения –

ответ

0

Использование Parallel LINQ вы можете написать:

var arguments = new double[] { 1d, 2d, 3d }; 
var result = arguments.AsParallel().Select(arg => Math.Sqrt(arg)); 

Это вычислить квадратный корень каждого аргумента параллельно. Это то, чего вы пытаетесь достичь?

+0

. Ваше решение даст аналогичный результат тому, чего я пытаюсь достичь в этом конкретном случае. Но представьте, что я пытался использовать настоящий метод Async, например HttpWebRequest.BeginGetResponse. В этом случае ваше решение будет выполнять только два одновременных запроса в двухъядерной машине, в то время как я пытаюсь достичь чего-то вроде 30 одновременных запросов. –

+0

AFAIK количество потоков, используемых PLINQ, динамически настраивается на оптимальное значение вашего аппарата: оно не зависит от количества ваших процессоров/ядер, что было бы глупо. – dtb

+0

Вы пропустили точку, пожалуйста, обратите внимание на порядок: 2 x 30. Хотя некоторые запросы отправляются, новые могут начинаться. –

Смежные вопросы