62 votes

Écrire une API async / non-async bien conçue

Je suis confronté au problème de la conception des méthodes qui effectue avec des e/S réseau (pour une bibliothèque réutilisable). J'ai lu cette question

c# 5 attendent/async modèle dans la conception d'API

et aussi d'autres plus proches de mon problème.

Donc, la question est, si je veux offrir à la fois asynchrone et non asynchrone de la méthode que j'ai pour la conception de ceux-ci?

Par exemple, pour exposer un non-async version de la méthode, j'ai besoin de faire quelque chose comme

public void DoSomething() {
  DoSomethingAsync(CancellationToken.None).Wait();
}

et je pense que c'est pas un super design. J'aimerais une suggestion (par exemple) sur la façon de définir les méthodes privées qui peuvent être enroulés dans les établissements publics de fournir les deux versions.

77voto

Stephen Cleary Points 91731

Si vous voulez le plus maintenable option, seulement un async API, qui est mis en œuvre sans faire aucun blocage des appels ou en utilisant n'importe quel thread du pool de threads.

Si vous voulez vraiment avoir les deux async et synchrone Api, vous rencontrerez un de maintenabilité problème. Vous avez vraiment besoin de mettre en œuvre deux fois: une fois async et une fois synchrone. Ces deux méthodes semblent presque identiques de sorte que la mise en œuvre initiale est facile, mais vous allez vous retrouver avec deux presque identiques des méthodes de maintenance est problématique.

En particulier, il n'y a pas de bonne façon simple et juste faire une async ou synchrone "wrapper". Stephen Toub a la meilleure info sur le sujet:

  1. Dois-je exposer asynchrone des wrappers pour les méthodes synchrones?
  2. Dois-je exposer synchrone des wrappers pour des méthodes asynchrones?

(la réponse à ces deux questions est "non")

3voto

Lorenzo Dematté Points 3082

Je suis d'accord avec les deux Marc et Stephen (Cleary).

(BTW, j'ai commencé à écrire ceci dans un commentaire de Stephen réponse, mais il s'est avéré être trop long; laissez-moi savoir si il est OK pour écrire cela comme une réponse ou non, et n'hésitez pas à prendre bits et l'ajouter à Stephen de répondre, dans l'esprit de "fournir la meilleure réponse").

C'est vraiment "dépend": comme Marc l'a dit, il est important de savoir comment DoSomethingAsync est asynchrone. Nous convenons tous qu'il est inutile d'avoir un "sync" appel de la méthode de la "async" méthode et "attendre": cela peut être fait dans le code de l'utilisateur. Le seul avantage d'avoir une méthode distincte est d'avoir de réels gains de performance, de mise en œuvre qui est, sous le capot, différents et adaptés à la machine synchrone scénario. Cela est particulièrement vrai si la "async" la méthode est la création d'un thread (ou de le prendre à partir d'un pool de threads): vous vous retrouvez avec quelque chose en dessous utilise deux "contrôle de flux", tandis que "prometteur" avec son synchrone semble être exécutée dans les appelants' contexte. Cela peut même avoir des problèmes de concurrence, en fonction de la mise en œuvre.

Dans d'autres cas, comme dans l'intensifs d'e/S que l'OP est de mentionner, il peut être utile d'avoir deux différents de mise en œuvre. La plupart des systèmes d'exploitation (Windows, pour sûr) ont pour I/O différents mécanismes adaptés pour les deux scénarios: par exemple, async exécution des e/S et l'opération prend beaucoup d'avantages au niveau de l'OS, des mécanismes comme I/O ports d'achèvement, ce qui ajoute un peu de surcharge (pas significatif, mais pas nulle) dans le noyau (après tout, ils ont pour faire la comptabilité, expédition, etc.), et la plus directe de mise en œuvre pour les opérations synchrones. La complexité du Code varie également beaucoup, en particulier dans les fonctions où plusieurs opérations sont effectuées/coordonné.

Ce que je voudrais faire c'est:

  • ont quelques exemples/test pour le type d'utilisation et scénarios
  • voir les API variante est utilisée, où, et à mesurer. La mesure de la différence de performances entre un "pur" sync " de la variante et "sync". (pas pour l'ensemble de l'API, mais pour certains quelques cas typiques)
  • basé sur la mesure, décider si le coût en vaut la peine.

Ce principalement parce que les deux objectifs sont en quelque sorte en contraste l'un avec l'autre. Si vous souhaitez code maintenable, le choix évident est la mise en œuvre de la synchronisation en termes de async/attente (ou l'inverse) (ou, encore mieux, de fournir seulement la async variante et de permettre à l'utilisateur de faire "attendre"); si vous voulez des résultats, vous devrez mettre en œuvre les deux fonctions différemment, pour exploiter des différents mécanismes sous-jacents (à partir du cadre ou de l'OS). Je pense qu'il ne devrait pas faire de différence à partir d'un test unitaire du point de vue de la façon dont vous avez réellement mettre en œuvre votre API.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X