Question

Je me méfie généralement de la mise en œuvre partielle d’interfaces. Cependant, IAsyncResult est un cas à part, car il prend en charge plusieurs modèles d’utilisation très différents. À quelle fréquence utilisez-vous / voyez-vous utilisé le motif AsyncState / AsyncCallback , par opposition à simplement appeler EndInvoke , en utilisant AsyncWaitHandle , ou interrogation IsCompleted (beurk)?

Question associée: Détecter qu'un objet ThreadPool WorkItem a été créé. terminé / en attente de fin .

Considérez cette classe (très approximative, verrouillage nécessaire):

public class Concurrent<T> {
    private ManualResetEvent _resetEvent;
    private T _result;

    public Concurrent(Func<T> f) {
        ThreadPool.QueueUserWorkItem(_ => {
                                         _result = f();
                                         IsCompleted = true;
                                         if (_resetEvent != null)
                                             _resetEvent.Set();
                                     });
    }

    public WaitHandle WaitHandle {
        get {
            if (_resetEvent == null)
                _resetEvent = new ManualResetEvent(IsCompleted);
            return _resetEvent;
        }

    public bool IsCompleted {get; private set;}
    ...

Il a WaitHandle (créé paresseux, comme décrit dans la documentation IAsyncResult ) et IsCompleted , mais je ne vois pas d'implémentation raisonnable pour AsyncState ( {return null;} ?). Cela a-t-il donc un sens de mettre en œuvre IAsyncResult ? Notez que la Tâche de la bibliothèque Parallel Extensions implémente IAsyncResult , mais seul IsCompleted est implémenté implicitement.

Était-ce utile?

La solution

  • D'après mon expérience, il est rarement utile d'appeler EndInvoke sans attendre ni être rappelé en premier
  • Fournir des rappels ne suffit parfois pas, car vos clients peuvent vouloir attendre plusieurs opérations à la fois (WaitAny, WaitAll)
  • Je n'ai jamais interrogé IsCompleted, beurk en effet! Vous pouvez donc enregistrer la mise en oeuvre de IsCompleted, mais c'est tellement simple que cela ne semble pas valoir la peine d'étonner potentiellement vos clients.

Ainsi, une implémentation raisonnable pour une méthode appelable de manière asynchrone devrait réellement fournir un IAsyncResult entièrement implémenté.

En passant, vous n'avez souvent pas besoin d'implémenter vous-même IAsyncResult, retournez simplement ce qui est retourné par Delegate.BeginInvoke. Voir l'implémentation de System.IO.Stream.BeginRead pour un exemple.

Autres conseils

Il semble que vous ayez quelques questions. Traitons-les individuellement

Créer WaitHandle paresseusement

Oui, c’est l’approche la plus correcte. Vous devez le faire de manière sécurisée au fil du temps, mais vous êtes paresseux.

L’astuce consiste toutefois à se débarrasser du WaitHandle. WaitHandle est une base de données identifiables et doit être éliminé rapidement. La documentation de IAsycResult ne couvre pas ce cas. La meilleure façon de faire est dans EndInvoke. La documentation de BeginInvoke indique explicitement que pour chaque BeginInvoke, il doit y avoir un EndInvoke (ou BeginRead / EndRead) correspondant. C’est le meilleur endroit pour disposer du WaitHandle.

Comment implémenter AsyncState?

Si vous examinez les API BCL standard qui renvoient un IAsyncResult, la plupart d’entre elles prennent un paramètre state. Il s'agit généralement de la valeur renvoyée par AsyncState (voir l'API Socket pour un exemple). Il est recommandé d'inclure une variable d'état typée en tant qu'objet pour toute API de style API BeginInvoke qui renvoie un IAsyncResult. Pas nécessaire mais bonne pratique.

En l'absence d'une variable d'état, renvoyer null est acceptable.

API IsCompleted

Cela dépendra beaucoup de l’implémentation qui crée IAsyncResult. Mais oui, vous devriez le mettre en œuvre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top