¿Cuándo usaría Tarea?Yield()?
Estoy usando async/await y Task
mucho, pero nunca he estado usando Task.Yield()
y para ser honesto, incluso con todas las explicaciones, no entiendo por qué necesitaría este método.
¿Puede alguien dar un buen ejemplo donde se requiere Yield()
?
3 answers
Cuando se usa async
/await
, no hay garantía de que el método que llame cuando lo haga await FooAsync()
se ejecute de forma asincrónica. La implementación interna es libre de regresar usando una ruta completamente sincrónica.
Si está haciendo una API donde es crítico que no bloquee y ejecute algún código de forma asincrónica, y existe la posibilidad de que el método llamado se ejecute de forma sincrónica (bloqueo efectivo), usando await Task.Yield()
forzará a su método a ser asincrónico, y devolverá el control a ese punto. El resto del código se ejecutará en un momento posterior (momento en el que todavía puede ejecutarse sincrónicamente) en el contexto actual.
Esto también puede ser útil si hace un método asíncrono que requiere alguna inicialización "de larga duración", es decir:
private async void button_Click(object sender, EventArgs e)
{
await Task.Yield(); // Make us async right away
var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later
await UseDataAsync(data);
}
Sin la llamada Task.Yield()
, el método se ejecutará sincrónicamente hasta la primera llamada a await
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-25 20:14:01
Internamente, await Task.Yield()
simplemente pone en cola la continuación en el contexto de sincronización actual o en un subproceso de grupo aleatorio, si SynchronizationContext.Current
es null
.
Es implementado eficientemente como awaiter personalizado. Un código menos eficiente que produce el efecto idéntico podría ser tan simple como esto:
var tcs = new TaskCompletionSource<bool>();
var sc = SynchronizationContext.Current;
if (sc != null)
sc.Post(_ => tcs.SetResult(true), null);
else
ThreadPool.QueueUserWorkItem(_ => tcs.SetResult(true));
await tcs.Task;
Task.Yield()
se puede utilizar como un atajo para algunas alteraciones extrañas del flujo de ejecución. Por ejemplo:
async Task DoDialogAsync()
{
var dialog = new Form();
Func<Task> showAsync = async () =>
{
await Task.Yield();
dialog.ShowDialog();
}
var dialogTask = showAsync();
await Task.Yield();
// now we're on the dialog's nested message loop started by dialog.ShowDialog
MessageBox.Show("The dialog is visible, click OK to close");
dialog.Close();
await dialogTask;
// we're back to the main message loop
}
Dicho esto, no puedo pensar en ningún caso donde Task.Yield()
no pueda ser reemplazado con Task.Factory.StartNew
w/ programador de tareas adecuado.
Véase también:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-20 03:08:52
Task.Yield()
puede ser usado en implementaciones simuladas de métodos asincrónicos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-11 13:45:05