1

async / await パターンを使用して、オブジェクトに対して CPU 負荷の高い操作を実行しています (私のメソッドは待機可能です)。これは、UI スレッドをブロックすることなく想定どおりに動作します。

ただし、オブジェクトをパラメーターとして新しいウィンドウの ctor に渡すと (新しいウィンドウは、処理されたオブジェクトへのアクセスが必要なログ ウィンドウです)、UI スレッドがブロックされます (理由はわかります)。

これを回避するには、計算の実行を

Task.Run(async () => { await _myObject.PerformCalculations(); });

そして、単に呼び出す

var logWindow = new LogWindow(_myObject);
logWindow.Show();

これは (もちろん) 機能しますが、オブジェクトがイベントを発生させたときに多くのディスパッチャー呼び出しが発生しますが、Task.Run 呼び出しなしで処理できれば対処する必要はありません。

それで、私の質問は、どうにかして Task.Run 呼び出しを行わずに、UI スレッドをブロックせずにオブジェクトをログ ウィンドウに渡すことができるかということです。

編集

簡素化された例で申し訳ありません。実際には、質問をできるだけ簡単に理解できるようにするつもりでしたが、惨めに失敗しました。

より一般的に言えば、特定の条件でイベントを発生させるオブジェクトがあります。イベントが発生したら、UI を更新したいと考えています。イベントは、Task.Run(...) を使用して作成されたスレッドから常に発生します。したがって、ディスパッチャーは UI スレッドを呼び出します。そのため、async / await (既に動作しています) を使用して計算を実行し、オブジェクトをログ ウィンドウ (ブロック) に渡したいと考えています。

Task.Run を使用すると、もちろんすべてが機能しますが、UI スレッドからオブジェクトのイベントをサブスクライブする場合は常に、Task.Run が作成したスレッドからイベントが発生するため、UI スレッドへのディスパッチャー呼び出しを使用する必要があります。これらのディスパッチャー呼び出しは避けたいと思います。実際、オブジェクトをロギング ウィンドウに渡さずに Show() メソッドを呼び出すと、UI スレッドはブロックされず、すべてが想定どおりに機能します。イベント ハンドラでディスパッチャを呼び出す必要はありません。

4

2 に答える 2

1

自分の状況を明確に把握するのはちょっと難しいです。しかし、リファクタリングを行うことでできるように思えます。

考慮してください:これは、 CPUを大量に使用する(したがって、実際にはPerformCalculationsフレンドリーではない)メソッドを返すTask(したがって、フレンドリーであると宣伝します)。最初に確認することは、CPU にバインドされた部分が独自の を使用するようにロジックを分割し、CPU に(直接) ヒットしないメソッドとして残すことです。async asyncPerformCalculationsTask.RunPerformCalcuationsasync

public async Task PerformCalculationsAsync()
{
  while (...)
  {
    await Task.Run(<next calculations>);
    RaiseEvent();
  }
}

このリファクタリングのポイントは、Task.Runイベントを発生させる UI っぽいコードから CPU コードを分割することです。IProgress<T>また、イベントが論理的な進行状況の更新である場合、またはこの種のリファクタリングがコードにとって難しすぎる場合は、標準的なアプローチの使用を検討してください。IProgress<T>.Report任意のスレッドから呼び出すことができます。

asyncまた、コンストラクターasyncプロパティ(特にデータ バインディングのセクション)に関する私の記事も参考になるかもしれません。

于 2013-03-15T12:22:21.703 に答える
0
// awaitable as well - await this in another async void/Task method (e.g. commanding)
public async Task MyAsyncProcess()
{
    await _myObject.PerformCalculations();
    var logWindow = new LogWindow(_myObject);
}

Task.Run()非同期メソッドを同期的に実行するため、この場合、async/await パターンをほとんど使用していません。コードを実行するメソッドも作成asyncし、別の場所で待機します。または、代わりにいくつかのFireAndForgetロジックを使用します。

于 2013-03-15T08:11:33.660 に答える