En el siguiente código, debido a la interfaz, la clase LazyBar
debe devolver una tarea de su método (y por el bien de los argumentos no se puede cambiar). Si LazyBar
la implementación de s es inusual en el sentido de que se ejecuta de forma rápida y sincrónica, ¿cuál es la mejor manera de devolver una tarea Sin operación del método?
He seguido a Task.Delay(0)
continuación, sin embargo, me gustaría saber si esto tiene algún efecto secundario en el rendimiento si la función se llama mucho (por el bien de los argumentos, digamos cientos de veces por segundo):
- ¿Este azúcar sintáctico se desenrolla en algo grande?
- ¿Comienza a obstruir el grupo de subprocesos de mi aplicación?
- ¿El compilador es suficiente para tratar de manera
Delay(0)
diferente? - ¿
return Task.Run(() => { });
Sería diferente?
¿Hay una mejor manera?
using System.Threading.Tasks;
namespace MyAsyncTest
{
internal interface IFooFace
{
Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
}
/// <summary>
/// An implementation, that unlike most cases, will not have a long-running
/// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
/// </summary>
internal class LazyBar : IFooFace
{
#region IFooFace Members
public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
{
// First, do something really quick
var x = 1;
// Can't return 'null' here! Does 'Task.Delay(0)' have any performance considerations?
// Is it a real no-op, or if I call this a lot, will it adversely affect the
// underlying thread-pool? Better way?
return Task.Delay(0);
// Any different?
// return Task.Run(() => { });
// If my task returned something, I would do:
// return Task.FromResult<int>(12345);
}
#endregion
}
internal class Program
{
private static void Main(string[] args)
{
Test();
}
private static async void Test()
{
IFooFace foo = FactoryCreate();
await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations();
return;
}
private static IFooFace FactoryCreate()
{
return new LazyBar();
}
}
}
Task.FromResult<object>(null)
.Respuestas:
Usar
Task.FromResult(0)
oTask.FromResult<object>(null)
generará menos gastos generales que crear unTask
con una expresión no operativa. Al crear unTask
resultado predeterminado, no hay gastos generales de programación involucrados.Hoy, recomendaría usar Task.CompletedTask para lograr esto.
fuente
return default(YourReturnType);
Task.CompletedTask
podría hacer el truco! (pero requiere .net 4.6)Para agregar a la respuesta de Reed Copsey sobre el uso
Task.FromResult
, puede mejorar el rendimiento aún más si almacena en caché la tarea ya completada, ya que todas las instancias de tareas completadas son iguales:Con
TaskExtensions.CompletedTask
usted puede usar la misma instancia en todo el dominio de la aplicación.La última versión de .Net Framework (v4.6) agrega solo eso con la
Task.CompletedTask
propiedad estáticafuente
public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
lo mismo quepublic async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
. Entonces, podemosreturn CompletedTask;
o bienawait CompletedTask;
. ¿Qué es más preferible (quizás más eficiente o más congruente)?Task.Delay(0)
como en la respuesta aceptada fue un buen enfoque, ya que es una copia en caché de un completadoTask
.A partir de 4.6, ahora
Task.CompletedTask
hay un propósito más explícito, pero no soloTask.Delay(0)
devuelve una sola instancia en caché, sino que también devuelve la misma instancia en cachéTask.CompletedTask
.La naturaleza de la caché ni se garantiza que se mantiene constante, pero como optimizaciones dependientes de la implementación que sólo depende de la implementación como optimizaciones (es decir, que todavía iba a trabajar correctamente si la aplicación cambia a algo que todavía era válida) el uso de la
Task.Delay(0)
era mejor que la respuesta aceptada.fuente
Task.CompletedTask
no puedo usarlo en un proyecto PCL, incluso si configuro la versión .net en 4.6 (perfil 7), que acabo de probar en VS2017.Task.CompletedTask => Task.Delay(0);
para admitir eso, así que no No estoy seguro de la parte superior de mi cabeza.Recientemente encontré esto y seguí recibiendo advertencias / errores sobre el método que se anula.
Estamos en el negocio de aplacar el compilador y esto lo aclara:
Esto reúne el mejor de todos los consejos aquí hasta ahora. No es necesaria una declaración de devolución a menos que realmente esté haciendo algo en el método.
fuente
public Task MyVoidAsyncMethod() {}
es completamente el mismo que el método anterior. Si hay un caso de uso para usarlo así, agregue el código adicional.fuente
Cuando debe devolver el tipo especificado:
fuente
Prefiero la
Task completedTask = Task.CompletedTask;
solución de .Net 4.6, pero otro enfoque es marcar el método como asíncrono y devolver vacío:Recibirá una advertencia (CS1998 - Función asíncrona sin esperar expresión), pero es seguro ignorarla en este contexto.
fuente
Si está utilizando genéricos, todas las respuestas nos darán un error de compilación. Puedes usar
return default(T);
. Muestra a continuación para explicar más.fuente
fuente