Linqpad runs continuations on the same thread most of the time with TaskScheduler.Default
Running this code on LinqPad 8.3 x64, .NET 6 runtime, .NET 7 host will almost always output the same threadId number
void Main() { TaskFactory tf = new TaskFactory(CancellationToken.None, TaskCreationOptions.RunContinuationsAsynchronously, TaskContinuationOptions.None, // Default supposed to be Asynchronous TaskScheduler.Default); tf.StartNew(() => { Thread.Sleep(1000); Console.WriteLine(Thread.CurrentThread.ManagedThreadId); }).ContinueWith(t => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); }, TaskScheduler.Default); Thread.Sleep(2000); }
Running this as a separate console application with VS2019 always outputs different thread IDs.
Are there some LinqPad specifics that make the Task.Scheduler.Default (supposed to be the thread pool task schedler) schedule on the same thread?
The same happens even if we really wanted to force the issue like this
tf.StartNew(() => { Thread.Sleep(1000); Console.WriteLine(Thread.CurrentThread.ManagedThreadId); }).ContinueWith(t => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); }, CancellationToken.None, TaskContinuationOptions.RunContinuationsAsynchronously, TaskScheduler.Default);
same with Task.Run
Task.Run(() => Console.WriteLine(Thread.CurrentThread.ManagedThreadId)) .ContinueWith(t => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); } , TaskContinuationOptions.RunContinuationsAsynchronously); Thread.Sleep(2000);
Comments
LINQPad doesn't do anything to mess with the task scheduler.
As I understand, the asynchronous continuation option determines behavior. It makes no guarantees about which thread the continuation will run on - that is an implementation detail. The TPL can still provide asynchronous behavior while re-using the same underlying thread. I suspect what's happening in your case is that the thread used for the first task is returned to the threadpool fast enough to be re-used for the next scheduled task. Whether or not this occurs is down to a race; therefore the output of this program is indeterminate.