usar puede programacion net hilos hebras funciones ejemplos ejemplo ejecutar ejecucion await async asp asincrona c# .net async-await dry

c# - puede - El uso de async aguarda cuando se implementa una biblioteca con API síncrona y asíncrona para la misma funcionalidad



programacion asincrona c# ejemplos (2)

En términos generales, las API deben ser asincrónicas o sincrónicas. Por ejemplo, si su implementación incluye E / S, debería ser asíncrona.

Dicho esto, hay escenarios en los que desea tener API síncronas y asíncronas. Por ejemplo, si el trabajo es naturalmente asincrónico, pero las API síncronas deben mantenerse para compatibilidad con versiones anteriores.

Si estás en esa situación, te recomiendo usar el truco de argumentos booleanos para minimizar la cantidad de código duplicado. Las envolturas asincrónicas sobre los métodos síncronos y las envolturas síncronas sobre los métodos asíncronos son ambos antipatrones.

Tengo algunas preguntas sobre cómo proporcionar implementación sincrónica y asíncrona de la misma funcionalidad en una biblioteca. Voy a preguntarles primero y luego les doy el siguiente código de ejemplo (que en realidad es un poco, pero de hecho es bastante simple).

  1. ¿Existe un enfoque para evitar violar el principio DRY? Considere las implementaciones de JsonStreamReader.Read , JsonStreamWriter.Write , JsonStreamWriter.Flush , ProtocolMessenger.Send , ProtocolMessenger.Receive y sus versiones asincrónicas.

  2. ¿Existe un enfoque para evitar violar el principio DRY cuando la unidad prueba versiones sincrónicas y asíncronas del mismo método? Estoy usando NUnit, aunque supongo que todos los marcos deberían ser los mismos a este respecto.

  3. ¿Cómo debería implementarse un método que devuelva Task o Task<Something> considerando las variantes Take 1 y Take 2 de ComplexClass.Send y ComplexClass.Receive ? ¿Cuál es correcto y por qué?

  4. ¿Es correcto incluir siempre .ConfigureAwait(false) después de await en una biblioteca teniendo en cuenta que no se sabe dónde se usará la biblioteca (aplicación de consola, Windows Forms, WPF, ASP.NET)?

Y aquí sigue el código al que me refiero en las primeras preguntas.

IWriter y JsonStreamWriter :

public interface IWriter { void Write(object obj); Task WriteAsync(object obj); void Flush(); Task FlushAsync(); } public class JsonStreamWriter : IWriter { private readonly Stream _stream; public JsonStreamWriter(Stream stream) { _stream = stream; } public void Write(object obj) { string json = JsonConvert.SerializeObject(obj); byte[] bytes = Encoding.UTF8.GetBytes(json); _stream.Write(bytes, 0, bytes.Length); } public async Task WriteAsync(object obj) { string json = JsonConvert.SerializeObject(obj); byte[] bytes = Encoding.UTF8.GetBytes(json); await _stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); } public void Flush() { _stream.Flush(); } public async Task FlushAsync() { await _stream.FlushAsync().ConfigureAwait(false); } }

IReader y JsonStreamReader :

public interface IReader { object Read(Type objectType); Task<object> ReadAsync(Type objectType); } public class JsonStreamReader : IReader { private readonly Stream _stream; public JsonStreamReader(Stream stream) { _stream = stream; } public object Read(Type objectType) { byte[] bytes = new byte[1024]; int bytesRead = _stream.Read(bytes, 0, bytes.Length); string json = Encoding.UTF8.GetString(bytes, 0, bytesRead); object obj = JsonConvert.DeserializeObject(json, objectType); return obj; } public async Task<object> ReadAsync(Type objectType) { byte[] bytes = new byte[1024]; int bytesRead = await _stream.ReadAsync(bytes, 0, bytes.Length).ConfigureAwait(false); string json = Encoding.UTF8.GetString(bytes, 0, bytesRead); object obj = JsonConvert.DeserializeObject(json, objectType); return obj; } }

IMessenger y ProtocolMessenger :

public interface IMessenger { void Send(object message); Task SendAsync(object message); object Receive(); Task<object> ReceiveAsync(); } public interface IMessageDescriptor { string GetMessageName(Type messageType); Type GetMessageType(string messageName); } public class Header { public string MessageName { get; set; } } public class ProtocolMessenger : IMessenger { private readonly IMessageDescriptor _messageDescriptor; private readonly IWriter _writer; private readonly IReader _reader; public ProtocolMessenger(IMessageDescriptor messageDescriptor, IWriter writer, IReader reader) { _messageDescriptor = messageDescriptor; _writer = writer; _reader = reader; } public void Send(object message) { Header header = new Header(); header.MessageName = _messageDescriptor.GetMessageName(message.GetType()); _writer.Write(header); _writer.Write(message); _writer.Flush(); } public async Task SendAsync(object message) { Header header = new Header(); header.MessageName = _messageDescriptor.GetMessageName(message.GetType()); await _writer.WriteAsync(header).ConfigureAwait(false); await _writer.WriteAsync(message).ConfigureAwait(false); await _writer.FlushAsync().ConfigureAwait(false); } public object Receive() { Header header = (Header)_reader.Read(typeof(Header)); Type messageType = _messageDescriptor.GetMessageType(header.MessageName); object message = _reader.Read(messageType); return message; } public async Task<object> ReceiveAsync() { Header header = (Header)await _reader.ReadAsync(typeof(Header)).ConfigureAwait(false); Type messageType = _messageDescriptor.GetMessageType(header.MessageName); object message = await _reader.ReadAsync(messageType).ConfigureAwait(false); return message; } }

ComplexClass :

public interface ISomeOtherInterface { void DoSomething(); } public class ComplexClass : IMessenger, ISomeOtherInterface { private readonly IMessenger _messenger; private readonly ISomeOtherInterface _someOtherInterface; public ComplexClass(IMessenger messenger, ISomeOtherInterface someOtherInterface) { _messenger = messenger; _someOtherInterface = someOtherInterface; } public void DoSomething() { _someOtherInterface.DoSomething(); } public void Send(object message) { _messenger.Send(message); } // Take 1 public Task SendAsync(object message) { return _messenger.SendAsync(message); } // Take 2 public async Task SendAsync(object message) { await _messenger.SendAsync(message).ConfigureAwait(false); } public object Receive() { return _messenger.Receive(); } // Take 1 public Task<object> ReceiveAsync() { return _messenger.ReceiveAsync(); } // Take 2 public async Task<object> ReceiveAsync() { return await _messenger.ReceiveAsync().ConfigureAwait(false); } }


La respuesta general aquí es que hacer versiones realmente async y sincronizadas de la misma funcionalidad requiere 2 implementaciones diferentes (tal vez similares, tal vez no) . Puede tratar de encontrar partes duplicadas y reutilizarlas usando una clase base (o una clase de utilidad) pero las implementaciones serían en su mayoría diferentes.

En muchos casos, las personas eligen suministrar solo una versión de la API, ya sea asíncrona o no. Por ejemplo, la biblioteca de cliente .Net para YouTube API v3 es completamente async . Si puedes pagar eso (muchos no pueden) esa sería mi recomendación.

Sobre sus preguntas específicas:

  1. No realmente, aparte de encontrar partes similares y abstraerlas.
  2. En realidad, no, los métodos síncronos deben probarse en un contexto síncrono mientras se sincronizan en un contexto async .
  3. Take 1 (es decir, devolver una tarea directamente) es preferible de 2 maneras:
    • Le falta la sobrecarga de crear toda la máquina de estado async innecesaria que agrega un aumento de rendimiento muy leve .
    • ConfigureAwait en este caso afecta solo al código que viene después, que en este caso no es ninguno. No afecta el código de la persona que llama si usa ConfigureAwait o no.
  4. Definitivamente sí (finalmente, positividad). async código async en las bibliotecas debe usar ConfigureAwait(false) de forma predeterminada, y eliminarlo solo cuando haya una necesidad específica de hacerlo.