parallel library async c# asynchronous .net-3.5 task-parallel-library task

c# - library - ¿Cómo puedo obtener el equivalente de Task<T> en.net 3.5?



task c# (4)

Use ThreadPool para ejecutar el método:

http://msdn.microsoft.com/en-us/library/kbf0f1ct(v=vs.110).aspx

Editar para Servy:

El programador predeterminado para Task Parallel Library y PLINQ usa .NET Framework ThreadPool para poner en cola y ejecutar el trabajo. En .NET Framework 4, ThreadPool usa la información que proporciona el tipo System.Threading.Tasks.Task para admitir de manera eficiente el paralelismo de granularidad (unidades de trabajo de corta duración) que a menudo representan tareas y consultas paralelas.

Editar 2 (debido a comentarios negativos):

Este código hace exactamente lo que el OP quiere:

void ReturnResponseAfterAShortDelay(WaitHandle cancellationToken) { log.InfoFormat("Deferring response for {0} ms", Settings.Default.TimeoutMs); ThreadPool.RegisterWaitForSingleObject(cancellationToken, () => { if (!cancellationToken.WaitOne(0)) { ReturnWhateverHasArrived(); } }, null, Settings.Default.TimeoutMs, true); }

Tengo un código que está usando la Task<T> que difiere la devolución de un resultado de una operación de lectura en serie durante un tiempo breve, como este:

void ReturnResponseAfterAShortDelay() { if (delayedResponseCancellationTokenSource != null) delayedResponseCancellationTokenSource.Cancel(); // Cancel any pending operations and start a new one. delayedResponseCancellationTokenSource = new CancellationTokenSource(); log.InfoFormat("Deferring response for {0} ms", Settings.Default.TimeoutMs); Task.Delay(Properties.Settings.Default.TimeoutMs, delayedResponseCancellationTokenSource.Token) .ContinueWith((continuation) => ReturnWhateverHasArrived(), TaskContinuationOptions.NotOnCanceled) .Start(); }

La idea detrás de este código es devolver el resultado cuando no han llegado nuevos caracteres durante un intervalo específico.

Sin embargo, debido a factores fuera de mi control, debo usar .NET 3.5, lo que me impide usar la Task<T> , así que tengo que refactorizar este código de alguna manera.

¿Cómo puedo lograr el mismo resultado sin usar la Task<T> ?

Aclaración

Aunque el código específico que mostré pasa a ser un retraso programado, mi uso no se limita a retrasar las cosas. Puede haber otros casos en los que desee iniciar inmediatamente una tarea de sondeo de ''larga ejecución''. Una situación típica sería una operación de E / S ligada, por ejemplo, algo que periódicamente consulta un dispositivo conectado al puerto serie y luego genera un evento cuando se cumple alguna condición.


Use un Timer (que en realidad es cómo el Delay se implementa internamente).

private static HashSet<Timer> timers = new HashSet<Timer>(); public static void ExecuteAfter(Action action, TimeSpan delay) { Timer timer = null; timer = new System.Threading.Timer(s => { action(); timer.Dispose(); lock (timers) timers.Remove(timer); }, null, (long)delay.TotalMilliseconds, Timeout.Infinite); lock (timers) timers.Add(timer); }

Para su edición, si está utilizando una aplicación asíncrona construida sobre un IO asíncrono, ese IO asíncrono ya expondrá algún método de asincronía. Podría ser un modelo basado en eventos, podría aceptar una devolución de llamada, podría estar usando IAsyncResult , etc. La Task es otro enfoque posible para la programación asincrónica, y ciertamente eres capaz de traducir cualquier enfoque a cualquier otro enfoque, si uno es Es preferible para ti, pero en general las personas tienden a seguir el método que utilizan los IO subyacentes que están utilizando, a menos que tengan alguna razón convincente para hacerlo de otra manera.


Aunque el código específico que mostré pasa a ser un retraso programado, mi uso no se limita a retrasar las cosas. Puede haber otros casos en los que desee iniciar inmediatamente una tarea de sondeo de ''larga ejecución''. Una situación típica sería una operación de E / S ligada, por ejemplo, algo que periódicamente consulta un dispositivo conectado al puerto serie y luego genera un evento cuando se cumple alguna condición.

Un truco notable y útil para codificar tales escenarios con C # 2.0 - 4.0 es usar IEnumerable y yield . Permite implementar una máquina de estado asíncrona, similar a async/await de C # 5.0. De esta forma, mantendrá el flujo de código lineal conveniente para su lógica asíncrona. Todas las sentencias de control del código del lenguaje C # funcionan (además de que no se puede hacer el yield return desde dentro de try/catch ).

Por ejemplo, una aplicación de consola con un temporizador:

using System; using System.Collections; using System.Threading; namespace ConsoleApplication_22516303 { class Program { class AsyncLogic { public EventHandler Completed = delegate { }; IEnumerable WorkAsync(Action nextStep) { using (var timer = new System.Threading.Timer(_ => nextStep())) { timer.Change(0, 500); var tick = 0; while (tick < 10) { // resume upon next timer tick yield return Type.Missing; Console.WriteLine("Tick: " + tick++); } } this.Completed(this, EventArgs.Empty); } public void Start() { IEnumerator enumerator = null; Action nextStep = () => enumerator.MoveNext(); enumerator = WorkAsync(nextStep).GetEnumerator(); nextStep(); } } static void Main(string[] args) { var mre = new ManualResetEvent(false); var asyncLogic = new AsyncLogic(); asyncLogic.Completed += (s, e) => mre.Set(); asyncLogic.Start(); mre.WaitOne(); Console.WriteLine("Completed, press Enter to exit"); Console.ReadLine(); } } }

Cualquier evento podría ser envuelto con un controlador que llamaría a nextStep , similar a la devolución de llamada del temporizador anterior. El código continuará después del yield return correspondiente, después del evento.

Hay bastantes implementaciones que aprovechan este enfoque, por ejemplo, AsyncEnumerator Jeffrey Richter .


Puede usar cualquiera de los siguientes paquetes disponibles a través de NuGet:

  • Puede usar el paquete TaskParallelLibrary en NuGet. Este paquete tiene un nombre fuerte y es un puerto posterior .NET 3.5 de .NET Task Parallel Library para .NET 4 que se incluyó en las extensiones reactivas.

  • Puede usar el paquete System.Threading.Tasks.Unofficial en NuGet. Esta implementación alternativa utiliza la base de código Mono en lugar de la implementación de Microsoft. Tenga en cuenta que el conjunto incluido en este paquete no tiene un nombre fuerte, por lo que si su biblioteca usa nombres fuertes, esta no es una opción.