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

Maintenant, imaginez une méthode asynchrone au lieu de Math.Sqrt (je ne suis pas sûr que la méthode ci-dessous est une véritable méthode async, mais il se comporte à peu près comme un)Comment synchroniser les méthodes asynchrones?

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

Il n'y a pas de bonne façon d'appeler cette méthode sans diviser le code. Donc, synchronisons cette méthode asynchrone avec AutoResetEvent. J'ai créé une classe d'aide:

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(); 
    } 
} 

Avec cette classe, nous pouvons:

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

Cette solution, je crée en quelques minutes alors que je pensais à ce problème. Il existe une alternative native à cela? Je suis sûr que mes solutions ont des bugs, car il manque des verrous. Il y a une bibliothèque plus éprouvée pour le faire?

+0

Si je lis votre code correctement, 'BeginSqrt' ne fait rien du tout de façon asynchrone. Il passe juste la valeur de retour à un callback au lieu de le retourner ("continuation passing style"). Votre 'Synchronizer' est essentiellement un wrapper qui retourne' BeginSqrt' dans une méthode normale. Aucune simultanéité impliquée, donc pas de verrous requis. – dtb

+0

@dtb Vous avez raison, peut-être que je devrais le changer pour une vraie méthode asynchrone de clarification –

Répondre

0

En utilisant Parallel LINQ vous pouvez écrire:

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

Ce serait calculer la racine carrée de chaque argument en parallèle. Est-ce ce que vous essayez d'accomplir?

+0

votre solution donnerait un résultat similaire à ce que j'essaie d'atteindre dans ce cas précis. Mais imaginez que j'essayais d'utiliser une vraie méthode Async comme HttpWebRequest.BeginGetResponse. Dans ce cas, votre solution ne ferait que 2 demandes simultanées dans une machine à double cœur, alors que j'essaie de réaliser quelque chose comme 30 demandes simultanées. –

+0

AFAIK le nombre de threads utilisés par PLINQ est ajusté dynamiquement à l'optimum de votre machine: il n'est pas fixé au nombre de vos processeurs/cœurs ce qui serait bête. – dtb

+0

Vous avez manqué le point, s'il vous plaît prêter attention à l'ordre de grandeur: 2 x 30. Alors que certaines demandes sont sortantes, de nouvelles peuvent commencer. –

Questions connexes