Skip to content

Commit 6976124

Browse files
committed
Merge pull request #319 from sharwell/task-performance
Improve performance of chained tasks and avoid wrapping exceptions
2 parents dc50e5c + 299b9f6 commit 6976124

14 files changed

+1003
-885
lines changed

src/corelib/Core/CoreTaskExtensions.cs

Lines changed: 370 additions & 0 deletions
Large diffs are not rendered by default.

src/corelib/Core/ParallelExtensionsExtras/TaskExtrasExtensions.cs

Lines changed: 0 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -308,219 +308,5 @@ public static TaskStatus WaitForCompletionStatus(this Task task)
308308
return task.Status;
309309
}
310310
#endregion
311-
312-
#region Then
313-
/// <summary>Creates a task that represents the completion of a follow-up action when a task completes.</summary>
314-
/// <param name="task">The task.</param>
315-
/// <param name="next">The action to run when the task completes.</param>
316-
/// <returns>The task that represents the completion of both the task and the action.</returns>
317-
public static Task Then(this Task task, Action next)
318-
{
319-
if (task == null) throw new ArgumentNullException("task");
320-
if (next == null) throw new ArgumentNullException("next");
321-
322-
var tcs = new TaskCompletionSource<object>();
323-
task.ContinueWith(delegate
324-
{
325-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
326-
else if (task.IsCanceled) tcs.TrySetCanceled();
327-
else
328-
{
329-
try
330-
{
331-
next();
332-
tcs.TrySetResult(null);
333-
}
334-
catch (Exception exc) { tcs.TrySetException(exc); }
335-
}
336-
}, TaskScheduler.Default);
337-
return tcs.Task;
338-
}
339-
340-
/// <summary>Creates a task that represents the completion of a follow-up function when a task completes.</summary>
341-
/// <param name="task">The task.</param>
342-
/// <param name="next">The function to run when the task completes.</param>
343-
/// <returns>The task that represents the completion of both the task and the function.</returns>
344-
public static Task<TResult> Then<TResult>(this Task task, Func<TResult> next)
345-
{
346-
if (task == null) throw new ArgumentNullException("task");
347-
if (next == null) throw new ArgumentNullException("next");
348-
349-
var tcs = new TaskCompletionSource<TResult>();
350-
task.ContinueWith(delegate
351-
{
352-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
353-
else if (task.IsCanceled) tcs.TrySetCanceled();
354-
else
355-
{
356-
try
357-
{
358-
var result = next();
359-
tcs.TrySetResult(result);
360-
}
361-
catch (Exception exc) { tcs.TrySetException(exc); }
362-
}
363-
}, TaskScheduler.Default);
364-
return tcs.Task;
365-
}
366-
367-
/// <summary>Creates a task that represents the completion of a follow-up action when a task completes.</summary>
368-
/// <param name="task">The task.</param>
369-
/// <param name="next">The action to run when the task completes.</param>
370-
/// <returns>The task that represents the completion of both the task and the action.</returns>
371-
public static Task Then<TResult>(this Task<TResult> task, Action<TResult> next)
372-
{
373-
if (task == null) throw new ArgumentNullException("task");
374-
if (next == null) throw new ArgumentNullException("next");
375-
376-
var tcs = new TaskCompletionSource<object>();
377-
task.ContinueWith(delegate
378-
{
379-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
380-
else if (task.IsCanceled) tcs.TrySetCanceled();
381-
else
382-
{
383-
try
384-
{
385-
next(task.Result);
386-
tcs.TrySetResult(null);
387-
}
388-
catch (Exception exc) { tcs.TrySetException(exc); }
389-
}
390-
}, TaskScheduler.Default);
391-
return tcs.Task;
392-
}
393-
394-
/// <summary>Creates a task that represents the completion of a follow-up function when a task completes.</summary>
395-
/// <param name="task">The task.</param>
396-
/// <param name="next">The function to run when the task completes.</param>
397-
/// <returns>The task that represents the completion of both the task and the function.</returns>
398-
public static Task<TNewResult> Then<TResult, TNewResult>(this Task<TResult> task, Func<TResult, TNewResult> next)
399-
{
400-
if (task == null) throw new ArgumentNullException("task");
401-
if (next == null) throw new ArgumentNullException("next");
402-
403-
var tcs = new TaskCompletionSource<TNewResult>();
404-
task.ContinueWith(delegate
405-
{
406-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
407-
else if (task.IsCanceled) tcs.TrySetCanceled();
408-
else
409-
{
410-
try
411-
{
412-
var result = next(task.Result);
413-
tcs.TrySetResult(result);
414-
}
415-
catch (Exception exc) { tcs.TrySetException(exc); }
416-
}
417-
}, TaskScheduler.Default);
418-
return tcs.Task;
419-
}
420-
421-
/// <summary>Creates a task that represents the completion of a second task when a first task completes.</summary>
422-
/// <param name="task">The first task.</param>
423-
/// <param name="next">The function that produces the second task.</param>
424-
/// <returns>The task that represents the completion of both the first and second task.</returns>
425-
public static Task Then(this Task task, Func<Task> next)
426-
{
427-
if (task == null) throw new ArgumentNullException("task");
428-
if (next == null) throw new ArgumentNullException("next");
429-
430-
var tcs = new TaskCompletionSource<object>();
431-
task.ContinueWith(delegate
432-
{
433-
// When the first task completes, if it faulted or was canceled, bail
434-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
435-
else if (task.IsCanceled) tcs.TrySetCanceled();
436-
else
437-
{
438-
// Otherwise, get the next task. If it's null, bail. If not,
439-
// when it's done we'll have our result.
440-
try { next().ContinueWith(t => tcs.TrySetFromTask(t), TaskScheduler.Default); }
441-
catch (Exception exc) { tcs.TrySetException(exc); }
442-
}
443-
}, TaskScheduler.Default);
444-
return tcs.Task;
445-
}
446-
447-
/// <summary>Creates a task that represents the completion of a second task when a first task completes.</summary>
448-
/// <param name="task">The first task.</param>
449-
/// <param name="next">The function that produces the second task based on the result of the first task.</param>
450-
/// <returns>The task that represents the completion of both the first and second task.</returns>
451-
public static Task Then<T>(this Task<T> task, Func<T, Task> next)
452-
{
453-
if (task == null) throw new ArgumentNullException("task");
454-
if (next == null) throw new ArgumentNullException("next");
455-
456-
var tcs = new TaskCompletionSource<object>();
457-
task.ContinueWith(delegate
458-
{
459-
// When the first task completes, if it faulted or was canceled, bail
460-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
461-
else if (task.IsCanceled) tcs.TrySetCanceled();
462-
else
463-
{
464-
// Otherwise, get the next task. If it's null, bail. If not,
465-
// when it's done we'll have our result.
466-
try { next(task.Result).ContinueWith(t => tcs.TrySetFromTask(t), TaskScheduler.Default); }
467-
catch (Exception exc) { tcs.TrySetException(exc); }
468-
}
469-
}, TaskScheduler.Default);
470-
return tcs.Task;
471-
}
472-
473-
/// <summary>Creates a task that represents the completion of a second task when a first task completes.</summary>
474-
/// <param name="task">The first task.</param>
475-
/// <param name="next">The function that produces the second task.</param>
476-
/// <returns>The task that represents the completion of both the first and second task.</returns>
477-
public static Task<TResult> Then<TResult>(this Task task, Func<Task<TResult>> next)
478-
{
479-
if (task == null) throw new ArgumentNullException("task");
480-
if (next == null) throw new ArgumentNullException("next");
481-
482-
var tcs = new TaskCompletionSource<TResult>();
483-
task.ContinueWith(delegate
484-
{
485-
// When the first task completes, if it faulted or was canceled, bail
486-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
487-
else if (task.IsCanceled) tcs.TrySetCanceled();
488-
else
489-
{
490-
// Otherwise, get the next task. If it's null, bail. If not,
491-
// when it's done we'll have our result.
492-
try { next().ContinueWith(t => tcs.TrySetFromTask(t), TaskScheduler.Default); }
493-
catch (Exception exc) { tcs.TrySetException(exc); }
494-
}
495-
}, TaskScheduler.Default);
496-
return tcs.Task;
497-
}
498-
499-
/// <summary>Creates a task that represents the completion of a second task when a first task completes.</summary>
500-
/// <param name="task">The first task.</param>
501-
/// <param name="next">The function that produces the second task based on the result of the first.</param>
502-
/// <returns>The task that represents the completion of both the first and second task.</returns>
503-
public static Task<TNewResult> Then<TResult, TNewResult>(this Task<TResult> task, Func<TResult, Task<TNewResult>> next)
504-
{
505-
if (task == null) throw new ArgumentNullException("task");
506-
if (next == null) throw new ArgumentNullException("next");
507-
508-
var tcs = new TaskCompletionSource<TNewResult>();
509-
task.ContinueWith(delegate
510-
{
511-
// When the first task completes, if it faulted or was canceled, bail
512-
if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
513-
else if (task.IsCanceled) tcs.TrySetCanceled();
514-
else
515-
{
516-
// Otherwise, get the next task. If it's null, bail. If not,
517-
// when it's done we'll have our result.
518-
try { next(task.Result).ContinueWith(t => tcs.TrySetFromTask(t), TaskScheduler.Default); }
519-
catch (Exception exc) { tcs.TrySetException(exc); }
520-
}
521-
}, TaskScheduler.Default);
522-
return tcs.Task;
523-
}
524-
#endregion
525311
}
526312
}

src/corelib/Core/ReadOnlyCollectionPageExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ public static Task<ReadOnlyCollection<T>> GetAllPagesAsync<T>(this ReadOnlyColle
9191

9292
// continue with the next page
9393
currentTask = getNextPage();
94-
currentTask.ContinueWith(continuation);
94+
currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
9595
};
96-
currentTask.ContinueWith(continuation);
96+
currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
9797

9898

9999
return taskCompletionSource.Task;

0 commit comments

Comments
 (0)