una tiempo tareas tarea servicio programar programador proceso net job hora ejecutar determinada demonio crear cierto cada c# task-parallel-library

c# - tiempo - ¿Cuál es la forma correcta de encadenar tareas al devolver una tarea?



programar tarea en c# (3)

Lo estoy tanto con el uso de Tareas en C #, pero me confundo cuando intento devolver una Tarea desde un método y ese método hará múltiples tareas dentro de sí mismo. Entonces, ¿tengo mi método para girar una nueva tarea y luego hacer todo secuencialmente dentro de allí? Es difícil envolver mi cabeza haciendo todo con .ContinuarCon ()

Ejemplo:

public Task<string> GetSomeData(CancellationToken token) { return Task.Factory.StartNew(() => { token.ThrowIfCancellationRequested(); var initialData = GetSomeInteger(token).Result; return GetSomeString(initialData, token).Result; }); } public Task<int> GetSomeInteger(CancellationToken token) { return Task<int>.Factory.StartNew(() => { return 4; }, token); } public Task<string> GetSomeString(int value, CancellationToken token) { return Task<string>.Factory.StartNew(() => { return value.ToString(); }, token); }

No estoy seguro de cómo escribir este método para que use las Tareas correctamente. Supongo que siento que debería haber un .ContinuarWith allí o algo así.

Posible solución ??

public Task<string> GetSomeData(CancellationToken token) { return GetSomeInteger(token).ContinueWith((prevTask) => { return GetSomeString(prevTask.Result, token); }, token).Unwrap(); }


Aquí hay un método de extensión que construí para resolver esto. Trabaja en .Net 4+

public static Task<TNewResult> ContinueWith<T, TNewResult>(this Task<T> task, Func<Task<T>, Task<TNewResult>> continuationFunction, CancellationToken cancellationToken) { var tcs = new TaskCompletionSource<TNewResult>(); task.ContinueWith(t => { if (cancellationToken.IsCancellationRequested) { tcs.SetCanceled(); } continuationFunction(t).ContinueWith(t2 => { if (cancellationToken.IsCancellationRequested || t2.IsCanceled) { tcs.TrySetCanceled(); } else if (t2.IsFaulted) { tcs.TrySetException(t2.Exception); } else { tcs.TrySetResult(t2.Result); } }); }); return tcs.Task; }


En general, a menudo es mejor tratar de evitar la creación de nuevas tareas si ya está trabajando con métodos basados ​​en tareas. El encadenamiento de tareas en lugar de bloquear explícitamente reducirá la sobrecarga del sistema, ya que no mantendrá atado a un hilo de ThreadPool.

Dicho esto, a menudo es más simple bloquear solo lo que estás haciendo.

Tenga en cuenta que C # 5 hace esto mucho más simple, al proporcionar una API que le ofrece lo mejor de ambos:

public async Task<string> GetSomeData(CancellationToken token) { token.ThrowIfCancellationRequested(); var initialData = await SomeOtherMethodWhichReturnsTask(token); string result = await initialData.MethodWhichAlsoReturnsTask(token); return result; };

Editar después de la actualización:

Dado el nuevo código, no hay una manera fácil de encadenar esto directamente con ContinueWith . Hay un par de opciones. Puede usar msdn.microsoft.com/en-us/library/dd780917.aspx para convertir la Task<Task<string>> que crearía, es decir:

public Task<string> GetSomeData(CancellationToken token) { Task<Task<string>> task = GetSomeInteger(token) .ContinueWith(t => { return GetSomeString(t.Result, token); }, token); return task.Unwrap(); }

Alternativamente, puede manejar el desenvolvimiento de forma elegante con TaskCompletionSource<T> :

public Task<string> GetSomeData(CancellationToken token) { var tcs = new TaskCompletionSource<string>(); Task<int> task1 = GetSomeInteger(token); Task<Task<string>> task2 = task1.ContinueWith(t => GetSomeString(t.Result, token)); task2.ContinueWith(t => tcs.SetResult(t.Result.Result)); return tcs.Task; }

Esto permite que todo el proceso funcione sin crear una nueva tarea (que vincula un hilo de threadpool), y sin bloquear nunca.

Tenga en cuenta que probablemente desee agregar continuaciones en la cancelación, y use tcs.SetCancelled cuando también se solicitó una cancelación.


Sí, todo se ejecutará secuencialmente dentro de su tarea principal. Esto se debe a que llamar a la propiedad Resultado bloqueará el hilo actual hasta que el valor haya regresado.