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?
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
@dtb Vous avez raison, peut-être que je devrais le changer pour une vraie méthode asynchrone de clarification –