Assume I created a library containing such method:
Task MyLibraryMethodAsync()
{
var taskCompletionSource = new TaskCompletionSource<object>();
Action myWorkItem =
() =>
{
// Simulate some work.
// Actual work items depend on input params.
Thread.Sleep(TimeSpan.FromSeconds(1));
taskCompletionSource.SetResult(null);
};
// The next two lines is simplification for demonstration.
// I do not have access to the workerThread - it is created
// and managed for me by another lib.
// All I can do - is to post some short work items to it.
var workerThread = new Thread(new ThreadStart(myWorkItem));
workerThread.Start();
return taskCompletionSource.Task;
}
Any user of my lib can call MyLibraryMethodAsync
like this
await MyLibraryMethodAsync().ConfigureAwait(false);
VeryLongRunningMethod();
void VeryLongRunningMethod()
{
Thread.Sleep(TimeSpan.FromHours(1));
}
And here the problem comes – VeryLongRunningMethod
will be executed inside the taskCompletionSource.SetResult(null)
call and thus it will block workerThread
for a long period of time, which is not desired behavior because workerThread
is intended to run small portions of code (work items).
How do I substitute context / scheduler to a thread pool inside the returned task making await x.ConfigureAwait(false)
to continue on the thread pool, but not on the workerThread
?
The current solution I found is
Task MyLibraryMethodAsync()
{
// ...
return taskCompletionSource.Task
.ContinueWith(x => x.Result, TaskScheduler.Default);
}
However, I do not like it due to overhead it creates. May be more elegant solution exists?