¿Cómo implementaría algo que funciona de manera similar a la palabra clave Async CTP await
? ¿Existe una implementación simple que funcione como await
en todos los casos, o await
requiere implementaciones diferentes para diferentes escenarios?Cómo implementar aguardar sin Async CTP
Respuesta
await
siempre implica el mismo tipo de transformación, pero es muy doloroso. La biblioteca lado de await
no es demasiado complicada, pero lo difícil es que el compilador crea una máquina de estado para usted, permitiendo que la continuación vuelva al lugar correcto.
Es posible que mi uso hacky de bloques iteradores (retorno de rendimiento) podría simular algo similar ... pero sería bastante feo.
Di un DevExpress webinar on what the compiler is doing behind the scenes a few weeks ago - que muestra el código decompilado de un par de ejemplos, así como también explica cómo el compilador crea una tarea para devolver, y lo que el "awaiter" tiene que hacer. Puede serle útil.
Puede encontrar un seminario web que Jon mencionó en youtube aquí: http://www.youtube.com/watch?v=HpA2x_JvLD4 – ShitalShah
Hay algunas implementaciones y ejemplos de corutinas hechas de iteradores (rendimiento).
Uno de los ejemplos es Caliburn.Micro framework, que usa este patrón para operaciones de GUI asíncronas. Pero se puede generalizar fácilmente para el código asíncrono general.
El marco MindTouch DReAM implementa corrutinas en la parte superior del iterador que es funcionalmente muy similar a asíncrono/esperan:
async Task Foo() {
await SomeAsyncCall();
}
vs
IYield Result Foo() {
yield return SomeAsyncCall();
}
Result
es la versión del sueño de Task
. Los marcos dlls funcionan con .NET 2.0+, pero para construirlo necesita 3.5, ya que estamos usando mucha sintaxis 3.5 en estos días.
La nueva palabra clave await
tiene una semántica similar a la palabra clave yield return
existente, ya que ambos hacen que el compilador genere la máquina de estado de estilo de continuación para usted. Entonces es posible hackear algo usando iteradores que tienen algunos de los mismos comportamientos que el CTP Async.
Esto es lo que se vería.
public class Form1 : Form
{
private void Button1_Click(object sender, EventArgs e)
{
AsyncHelper.Invoke<bool>(PerformOperation);
}
private IEnumerable<Task> PerformOperation(TaskCompletionSource<bool> tcs)
{
Button1.Enabled = false;
for (int i = 0; i < 10; i++)
{
textBox1.Text = "Before await " + Thread.CurrentThread.ManagedThreadId.ToString();
yield return SomeOperationAsync(); // Await
textBox1.Text = "After await " + Thread.CurrentThread.ManagedThreadId.ToString();
}
Button2.Enabled = true;
tcs.SetResult(true); // Return true
}
private Task SomeOperationAsync()
{
// Simulate an asynchronous operation.
return Task.Factory.StartNew(() => Thread.Sleep(1000));
}
}
Desde yield return
genera un IEnumerable
nuestra co-rutina debe devolver un IEnumerable
. Toda la magia ocurre dentro del método AsyncHelper.Invoke
. Esto es lo que hace que funcione nuestra coroutine (enmascarada como un iterador pirateado). Se debe tener especial cuidado para asegurarse de que el iterador siempre se ejecute en el contexto de sincronización actual, si existe, lo cual es importante cuando se trata de simular cómo funciona await
en un subproceso de interfaz de usuario. Hace esto ejecutando el primer MoveNext
de forma síncrona y luego usando SynchronizationContext.Send
para hacer el resto de un subproceso de trabajo que también se usa para esperar asincrónicamente en los pasos individuales.
public static class AsyncHelper
{
public static Task<T> Invoke<T>(Func<TaskCompletionSource<T>, IEnumerable<Task>> method)
{
var context = SynchronizationContext.Current;
var tcs = new TaskCompletionSource<T>();
var steps = method(tcs);
var enumerator = steps.GetEnumerator();
bool more = enumerator.MoveNext();
Task.Factory.StartNew(
() =>
{
while (more)
{
enumerator.Current.Wait();
if (context != null)
{
context.Send(
state =>
{
more = enumerator.MoveNext();
}
, null);
}
else
{
enumerator.MoveNext();
}
}
}).ContinueWith(
(task) =>
{
if (!tcs.Task.IsCompleted)
{
tcs.SetResult(default(T));
}
});
return tcs.Task;
}
}
El conjunto poco sobre el TaskCompletionSource
fue mi intento de replicar la forma await
puede "retorno" un valor.El problema es que la coroutine tiene para realmente devolver un IEnumerable
ya que no es más que un iterador pirateado. Así que necesitaba encontrar un mecanismo alternativo para capturar un valor de retorno.
Hay algunas limitaciones flagrantes con esto, pero espero que esto le dé la idea general. También demuestra cómo el CLR podría tener tener un mecanismo generalizado para implementar corutinas para las cuales await
y yield return
usarían de forma ubicua, pero de diferentes maneras para proporcionar su semántica respectiva.
De mi lectura, las principales diferencias entre yield return
y await
pueden indicar que se devuelve explícitamente un nuevo valor en la continuación.
SomeValue someValue = await GetMeSomeValue();
mientras que con yield return
, que tendría que lograr lo mismo por referencia.
var asyncOperationHandle = GetMeSomeValueRequest();
yield return asyncOperationHandle;
var someValue = (SomeValue)asyncOperationHandle.Result;
Bill Wagner de Microsoft escribió an article in MSDN Magazine acerca de cómo se puede utilizar la biblioteca de tareas en paralelo en Visual Studio 2010 para aplicar asíncrono como el comportamiento sin añadir una dependencia en el CTP asíncrono.
Utiliza Task
y Task<T>
ampliamente que también tiene la ventaja añadida de que una vez C# 5 está fuera, su código estará bien preparado para empezar a utilizar async
y await
.
- 1. async/aguardar mecanismo de cancelación
- 2. async ctp recursion
- 3. ¿Por qué el async CTP funciona mal?
- 4. Async CTP: ¿cómo puedo usar async/await para llamar a un servicio wcf?
- 5. Async CTP: enfoque recomendado para la programación de tareas
- 6. Uso de Async CTP con la Biblioteca de clases portátil
- 7. ¿Se puede utilizar el CTP Async con una biblioteca portátil
- 8. Visual Studio Async CTP en vainilla .Net 4?
- 9. OperationContext.Current es nulo después de aguardar cuando se utiliza async/await en el servicio WCF
- 10. ¿Cómo implementar SQL CE 4 CTP para alojamiento compartido?
- 11. Implementar el patrón Async clásico con TPL
- 12. C# Async - ¿Cómo funciona?
- 13. ¿La recursión asíncrona es segura en C# (async ctp/.net 4.5)?
- 14. ¿Cómo implementar cierres sin gc?
- 15. async Task.Run con MVVM
- 16. Cómo implementar una aplicación web dirigida a Entity Framework 4.2 Junio de 2011 CTP
- 17. ¿Cómo hago una llamada jQuery bloqueando AJAX sin async = false?
- 18. HttpListener de subprocesos múltiples con aguardar asíncrono y tareas
- 19. ¿Puede resharper omitir las palabras clave async/await?
- 20. cómo agrego la extensión ctp en netbeans
- 21. implementar signalR sin jquery
- 22. Cómo implementar una API REST sin estado
- 23. CakePHP .ctp destacando en Eclipse
- 24. Implementar en iPhone sin ejecutar
- 25. MSBuild no encuentra las referencias requeridas async
- 26. Objective-C: Async/Background POST sin usar el método delegate?
- 27. Boost equivalente a std :: async()
- 28. Usando async-await en .net 4
- 29. ¿Por qué bloquea WebClient.DownloadStringTaskAsync()? - nueva API/sintaxis asíncrona/CTP
- 30. std :: async - std :: launch :: async | std :: launch :: deferred
Acabo de publicar un artículo sobre cómo [Esperar tareas en C# 4 usando Iteradores] (http://www.codeproject.com/Articles/504197/Await-Tasks-in-Csharp4-using-Iterators). Sorprendentemente, no es "hacky" ni muy feo, y AFAICT funciona igual de esperándolo. ¡Echale un vistazo! –