2009-10-08 9 views
0

J'apprends le threading.Mon intension est de passer certaines valeurs à une méthode de calcul, si le résultat ne sera pas retourné dans les 20 ms, je rapporterai "Operation timeout" .Basé sur mon understading j'ai implémenté le code comme suit :Comment signaler un délai d'attente dans un appel asynchrone?

public delegate long CalcHandler(int a, int b, int c); 


public static void ReportTimeout() 
    { 
     CalcHandler doCalculation = Calculate; 

     IAsyncResult asyncResult = 
     doCalculation.BeginInvoke(10,20,30, null, null); 

     if (!asyncResult.AsyncWaitHandle.WaitOne(20, false)) 
     { 
      Console.WriteLine("..Operation Timeout..."); 
     } 

     else 
     { 
     // Obtain the completion data for the asynchronous method. 
     long val; 
     try 
     { 
      val= doCalculation.EndInvoke(asyncResult); 
      Console.WriteLine("Calculated Value={0}", val); 
     } 
     catch 
     { 
      // Catch the exception 
     } 
    } 

    } 

public static long Calculate(int a,int b,int c) 
    { 
     int m; 
     //for testing timeout,sleep is introduced here. 
     Thread.Sleep(200); 
     m = a * b * c; 
     return m; 
    } 

questions:

(1) Est-ce la bonne façon de signaler délai d'attente? (2) Je n'appellerai pas EndInvoke(), si le temps est expiré. Dans ce cas, appeler EndInvoke() est obligatoire?

(3) J'entendu que

« Même si vous ne voulez pas gérer la valeur de retour de votre méthode asynchrone, vous devez appeler EndInvoke, sinon, vous risquez une fuite mémoire chaque fois que vous effectuez un appel asynchrone utilisant BeginInvoke "

Quel est le risque associé à la mémoire? peux-tu donner un exemple?

Répondre

2

Réponses

(1) En général, vous venez de jeter System.TimeoutException

(2) La raison EndInvoke() est nécessaire est que si les valeurs de retour (ou exceptions moulinée) ont des allocations de mémoire du GC peut ne pas le nettoyer aussi rapidement. Je n'ai pas vu un cas où c'était un gros problème ... mais c'est juste moi.

Si votre vraiment inquiet à ce sujet, vous pouvez simplement appeler ThreadPool.QueueUserWorkItem qui est principalement ce que l'invocation asynchrone ci-dessus va faire. (note: peut être un problème dans WinForms ou d'autres contextes dépendant du thread). De toute façon, vous pouvez exécuter votre propre travail comme suit:

public static long Calc(CalcHandler fn, int a, int b, int c) 
    { 
     return Run<long>(TimeSpan.FromSeconds(20), delegate { return fn(a, b, c); }); 
    } 

    public static T Run<T>(TimeSpan timeout, Func<T> operation) 
    { 
     Exception error = null; 
     T result = default(T); 

     ManualResetEvent mre = new ManualResetEvent(false); 
     System.Threading.ThreadPool.QueueUserWorkItem(
      delegate(object ignore) 
      { 
       try { result = operation(); } 
       catch (Exception e) { error = e; } 
       finally { mre.Set(); } 
      } 
     ); 
     if (!mre.WaitOne(timeout, true)) 
      throw new TimeoutException(); 
     if (error != null) 
      throw new TargetInvocationException(error); 
     return result; 
    } 
1

D'une valeur de délai d'attente, oui, cela va définir le délai d'attente comme vous vous y attendiez.

En ce qui concerne le risque de mémoire. Si vous n'appelez pas EndInvoke, il y a un risque que le délégué soit toujours référencé et que les ressources utilisées ne soient pas récupérées avant la fermeture de l'application. L'implémentation exacte n'est pas documentée à 100% à partir de ce que j'ai trouvé, mais pourrait être confirmée avec un outil comme ANTS Profiler.

Voici un discussion utile.

Questions connexes