-3

私はソケットの読み取りをループしているタスクがあります。

private async void readLoop() {
    while (!cts.IsCancelRequested()) {
        await socket.ReceiveAsync(data, ...);
        doWork(data);
    }
}

そして、タスクが作成されたらすぐに実行する必要はないので、私はTaskではなく、コンストラクターTask.Run

private Task readTask = new Task(readLoop, cts, LongRunning);
// when the task need to run:
readTask.Start()

この時点では、タスクを終了する必要があるときは、私が呼び出すときを除いて、それはうまく動作します。readTask.Wait()またはawait readTaskで例外が発生しましたReceiveAsyncまたはdoWorkに添付されていませんreadTask。例外があったとしても、readTask.StatusですRunToCompleteそしてreadTask.Exceptionですnull。アコード。ドキュメントによると、これはasyncメソッドがvoidを返すためですが、私がこれを試したとき:

private async Task readLoop() {...}

コンパイルされません:

error CS0407: 'Task WebSocketInitiator.readLoop()' has the wrong return type

タスクを後で開始し、同時にタスクで発生した例外を追跡し続けるようにする方法はありますか。

問題を示すための最小限のテストケースhttps://dotnetfiddle.net/JIfDIn


  • の可能な重複stackoverflow.com/questions/5383310/… - Peter Duniho
  • の可能な重複stackoverflow.com/questions/17923204/… - Peter Duniho
  • の可能な重複stackoverflow.com/questions/41742853/… - Peter Duniho
  • ここで一番下の行:あなたのasyncメソッドの戻り値voidこれは、呼び出し元のコードが例外を監視できないようにするためです。Task例外を表すことができるメソッドのため。あなたは使ってはいけませんasync voidこの文脈では、そうしないという推奨される方法に従えば、あなたの問題は起こらないでしょう。返品タイプを変更したときにCS0407が表示されるのはなぜでしょうか。あなたは他の場所でも間違いを犯したにちがいありません、しかし、あなたは善を提供しませんでした最小、完全、および検証可能な例それは確実に問題を再現するので、その問題が何であるか、誰も言うことができません。 - Peter Duniho
  • Task()は最初の引数としてActionを必要とし、actionは単にvoid foo(void);であるため、コンパイルに失敗しました。タスクfoo()を受け入れませんでした。 - fluter

2 답변


2

私があなたが正しく理解しているならば、あなたはそれが必要とされるまでタスクを実行することを延期したいです、しかし、あなたはコンストラクタで創造を続けたいです。それは結構です、そしてこのような状況のために使われるパターンがあります。それは呼ばれていますLazy

しかし、Lazyは非同期ではありません。Stephen TaubはAsyncLazyという非同期の実装を作成しました

表示されたエラーメッセージが表示されたのは、作成した外側のTaskの戻り値を指定しなかったためです。また戻る必要がありますfooの値内側のTaskを返すラムダで呼び出しをラップすると、それを取得することができます。

var task1 = new Task<Task>(async () => await foo(),
     CancellationToken.None, TaskCreationOptions.LongRunning);
task1.Start();

あなたがそれを待つとき、あなたはそれが返すタスクではなく外側のタスクを待つでしょう。そのため、展開する必要があります。

task1.Unwrap().Wait();

この方法であなたは例外を捕らえるでしょう。しかしながら、これはおそらくない最もよい方法は、Task.Run、async、およびawaitを使用する全体的な理由から、これらの構成要素を避けることでした。 結論として:

  • タスクの呼び出しを延期する必要がある場合は、AsyncLazyを使用してください。
  • Taskコンストラクタを呼び出さないでください
  • Task.Runを使用する


  • これは本当に役に立ちます、ありがとう! - fluter
  • ちょっと一口ですが、保存する前にアンラップするほうがおそらく良いでしょう。task1 - Kevin Gosse
  • @KevinGosseそれはいいことでしたが.Start()呼び出すことができません。 - Default
  • @Default良い点、私の悪い点 - Kevin Gosse

2

そして、タスクが作成されたらすぐに実行する必要はないので、私はTask.RunではなくTaskコンストラクターを使用しています。

タスクコンストラクタは絶対に使用しないでください。文字通り合理的なユースケースはありませんまったく

あなたの場合、デリゲートや遅延初期化、あるいはそのようなものは必要ないように思えます。メンバーとメソッドはプライベートなので、実行時にタスクメンバーを割り当てるのと同じくらい意味があります。

private async Task readLoop();

// when the task needs to run:
readTask = Task.Run(() => readLoop());

しかし、あなたが行う現在ではなく将来実行するコードを表す必要がある場合は、デリゲートが必要です。この場合、非同期デリゲートFunc<Task>

Func<Task> func = () => Task.Run(() => readLoop());
...
Task task = func();

リンクされた質問


関連する質問

最近の質問