Task is being scheduled on the same thread as the caller's

浪子不回头ぞ 提交于 2020-01-06 13:57:15

问题


My application has a View Model which contains a Lazy<BitmapImage> field. The field is populated using a service call to the server. In cases where the image is large, it takes a few seconds for the server to return the image (which is in fact a byte[]) therefore the UI is blocked. To prevent this, I put the service call in a Task, so that a background thread gets the image and then calls the OnPropertyChanged to let the UI know the image is returned:

Console.WriteLine("Outside Task ThreadID: {0}",
    Thread.CurrentThread.ManagedThreadId);

Task.Factory.StartNew(() =>
{
    Console.WriteLine("Inside Task ThreadID: {0}", Thread.CurrentThread.ManagedThreadId);

    return Utilities.ConvertByteToImage(
              SessionService.GetUserInformation(UserInfo.From).ProfilePicture);
}).ContinueWith(resultToken =>
{
    m_lazyProfilePicture = new Lazy<BitmapImage>(() =>
    {
        return (resultToken.Result == null) ? Utilities.DefaultProfilePicture.Value : resultToken.Result;
    });

    OnPropertyChanged("ProfilePicture");
});

I noticed that even after putting the service call in a Task, the UI is till blocked. So added those Console.WriteLine lines to see the thread IDs. Surprisingly enough, both of them report the same thread ID (this seems to happen only in this case.I tried it with other tasks in the project, and they all report different IDs). Any idea what's going on here? Does it have anything to do with the BitmapImage? For some reason the scheduler decides to put the task in the same thread, but I don't understand why. Any suggestions are welcome!


回答1:


StartNew doesn't ensure that the task is run in a new thread. It uses TaskScheduler.Current to schedule the new task. In many places throughout your code this will be null. When it is null, then TaskScheduler.Default will be used, which will schedule the delegate to run in the thread pool.

In your particular case Current is not null. It is the representation of some task scheduler that schedules the delegates to run in the UI thread.

One way this may have happened is if the code that you are running is the result of a call to StartNew or ContinueWith with the UI synchronization context. During the delegates executed in either case it will set the current scheduler to be one that is based on the SynchronizationContext provided, namely the UI context.

If you use Task.Run you avoid the issue; it will always use the default task scheduler instead of the current one.

Your other option is to explicitly state you want the default task scheduler:

Task.Factory.StartNew(() => { }
    , CancellationToken.None
    , TaskCreationOptions.None
    , TaskScheduler.Default);


来源:https://stackoverflow.com/questions/18882048/task-is-being-scheduled-on-the-same-thread-as-the-callers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!