1

私のアプリケーションには、フィールドを含むビュー モデルがありLazy<BitmapImage>ます。このフィールドは、サーバーへのサービス呼び出しを使用して入力されます。画像が大きい場合、サーバーが画像 (実際には a ) を返すのに数秒かかるbyte[]ため、UI がブロックされます。これを防ぐために、サービス コールを に配置Taskして、バックグラウンド スレッドが画像を取得し、 を呼び出してOnPropertyChanged、画像が返されたことを UI に知らせます。

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");
});

サービス コールを に配置した後でもTask、UI がブロックされるまで気付きました。そのため、これらの行を追加Console.WriteLineしてスレッド ID を確認しました。驚いたことに、両方とも同じスレッド ID を報告しています (これはこの場合にのみ発生するようです。プロジェクトの他のタスクで試してみたところ、すべて異なる ID が報告されました)。ここで何が起こっているのか分かりますか?と何か関係がありBitmapImageますか?何らかの理由で、スケジューラーはタスクを同じスレッドに入れることにしましたが、その理由がわかりません。どんな提案も大歓迎です!

4

1 に答える 1

8

StartNewタスクが新しいスレッドで実行されることを保証しません。TaskScheduler.Current新しいタスクをスケジュールするために使用します。コード全体の多くの場所で、これはnull. の場合はnullTaskScheduler.Defaultデリゲートがスレッド プールで実行されるようにスケジュールするために使用されます。

あなたの特定のケースCurrentではnullではありません。これは、デリゲートを UI スレッドで実行するようにスケジュールするタスク スケジューラの表現です。

これが発生した可能性がある 1 つの方法は、実行中のコードが UI 同期コンテキストへの呼び出しの結果であるStartNewContinueWith、UI 同期コンテキストを使用した結果である場合です。SynchronizationContextいずれの場合もデリゲートの実行中に、現在のスケジューラが提供されたもの、つまり UI コンテキストに基づくものに設定されます。

使用Task.Runすると、問題を回避できます。現在のタスク スケジューラではなく、常に既定のタスク スケジューラが使用されます。

もう 1 つのオプションは、既定のタスク スケジューラが必要であることを明示的に示すことです。

Task.Factory.StartNew(() => { }
    , CancellationToken.None
    , TaskCreationOptions.None
    , TaskScheduler.Default);
于 2013-09-18T21:02:50.853 に答える