Allen4Tech
Allen4Tech

Reputation: 2184

why the caller method and async method have the same thread id

please refer to my code below.

public MainViewModel()
    {
        LongRunningOperationCommand = new RelayCommand(ExecuteLongRunningOperationCommand);
    }

    private void ExecuteLongRunningOperationCommand()
    {
        Test();
    }

    private async Task Test()
    {
        Log += "Command begin: " + DateTime.Now + "\r\n";
        Log += "Command thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
        var getStringAsync = GetStringAsync();
        Log += "Work in Command...\r\n";
        Log += "Work in Command which not related to the result of async method will complete: " + DateTime.Now + "\r\n";
        Log += "Work in Command which not related to the result of async method will complete, thread: " +
               Thread.CurrentThread.ManagedThreadId + "\r\n";
        string result = await getStringAsync;
        Log += "Command will complete: " + DateTime.Now + "\r\n";
        Log += "Command will complete, thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
        Log += result + "\r\n";
    }

    private async Task<string> GetStringAsync()
    {
        Log += "Async method begin: " + DateTime.Now + "\r\n";
        Log += "Async method thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
        Log += "Work in Async method... \r\n";
        await Task.Delay(10000);
        Log += "Async method will complete: " + DateTime.Now + "\r\n";
        Log += "Async method will complete, thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
        return "GetStringAsync method completed!";
    }

The result as below

Command begin: 1/6/2016 11:58:37 PM
Command thread: 8
Async method begin: 1/6/2016 11:58:37 PM
Async method thread: 8
Work in Async method... 
Work in Command...
Work in Command which not related to the result of async method will complete: 1/6/2016 11:58:37 PM
Work in Command which not related to the result of async method will complete, thread: 8
Async method will complete: 1/6/2016 11:58:47 PM
Async method will complete, thread: 8
Command will complete: 1/6/2016 11:58:47 PM
Command will complete, thread: 8
GetStringAsync method completed!

The thread id after await Task.Delay in GetStringAsync method should be different with before. Why the result is the same? In Console application, the thread ids are different, but in WPF application, they're the same. Anyone can help?

Upvotes: 1

Views: 346

Answers (1)

Scott Chamberlain
Scott Chamberlain

Reputation: 127603

One of the big points of async/await is if you have a SynchronizationContext, like the WPF's DispatcherSynchronizationContext, work started on that thread will continue on that thread after the await unless you tell it not to.

Console applications do not have a SynchronizationContext so it uses the default context which schedules threads on the thread pool, that is why you see different behavior from WPF and a console app.

To tell async/await it does not need to keep on the same sync context you can use .ConfigureAwait(false) when you await, it will then use the default thread pool context to do the callback if needed.

private async Task Test()
{
    Log += "Command begin: " + DateTime.Now + "\r\n";
    Log += "Command thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
    var getStringAsync = GetStringAsync();
    Log += "Work in Command...\r\n";
    Log += "Work in Command which not related to the result of async method will complete: " + DateTime.Now + "\r\n";
    Log += "Work in Command which not related to the result of async method will complete, thread: " +
           Thread.CurrentThread.ManagedThreadId + "\r\n";
    string result = await getStringAsync.ConfigureAwait(false);
    Log += "Command will complete: " + DateTime.Now + "\r\n";
    Log += "Command will complete, thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
    Log += result + "\r\n";
}

private async Task<string> GetStringAsync()
{
    Log += "Async method begin: " + DateTime.Now + "\r\n";
    Log += "Async method thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
    Log += "Work in Async method... \r\n";
    await Task.Delay(10000).ConfigureAwait(false);
    Log += "Async method will complete: " + DateTime.Now + "\r\n";
    Log += "Async method will complete, thread: " + Thread.CurrentThread.ManagedThreadId + "\r\n";
    return "GetStringAsync method completed!";
}

Note, doing .ConfigureAwait(false) does not guarantee that the rest of the code will be on the thread pool, if the task is in the Completed state the code will execute synchronously and stay on whatever thread originally called await.

See the artice "It's All About the SynchronizationContext" for more info.

Upvotes: 6

Related Questions