409

私は並列プログラミングに不慣れです。.NETで使用できるクラスは2つあります:TaskThread

だから、私の質問は次のとおりです。

  • それらのクラスの違いは何ですか?
  • Threadいつ使用するのが良いTaskですか(またはその逆)?
4

3 に答える 3

502

Threadは低レベルの概念です。スレッドを直接開始する場合は、スレッドプールなどで実行するのではなく、別のスレッドになることがわかります。

Taskただし、これは「コードを実行する場所」の単なる抽象化ではありません。実際には、「将来の結果の約束」にすぎません。いくつかの異なる例として:

  • Task.Delay実際のCPU時間は必要ありません。タイマーを設定して将来オフにするようなものです
  • によって返されるタスクは、WebClient.DownloadStringTaskAsyncローカルで多くのCPU時間を必要としません。これは、ほとんどの時間をネットワーク遅延またはリモート作業(Webサーバーで)に費やす可能性が高い結果を表しています。
  • Task.Run()によって返されるタスクは、このコードを個別に実行してほしい」というものです。そのコードが実行される正確なスレッドは、いくつかの要因によって異なります。

Task<T>抽象化は、C#5での非同期サポートにとって極めて重要であることに注意してください。

一般に、可能な限り高レベルの抽象化を使用することをお勧めします。最新のC#コードでは、独自のスレッドを明示的に開始する必要はほとんどありません。

于 2012-11-17T09:03:57.337 に答える
49

通常、タスクはスレッドよりも高レベルの概念であると聞きます...そしてそれがこのフレーズの意味です:

  1. Abort / ThreadAbortedExceptionを使用することはできません。token.IsCancellationRequestedフラグを定期的にテストする「ビジネスコード」でキャンセルイベントをサポートする必要があります(dbへの長い接続やタイムアウトのない接続も避けてください。そうしないと、このフラグをテストする機会がありません)。同様の理由Thread.Sleep(delay)で、呼び出しを呼び出しに置き換える必要があり Task.Delay(delay, token)ます(遅延を中断する可能性があるためにトークンを内部に渡す)。

  2. タスクにはスレッドSuspendResumeメソッドの機能はありません。タスクのインスタンスも再利用できません

  3. しかし、2つの新しいツールがあります。

    a)継続

    // continuation with ContinueWhenAll - execute the delegate, when ALL
    // tasks[] had been finished; other option is ContinueWhenAny
    
    Task.Factory.ContinueWhenAll( 
       tasks,
       () => {
           int answer = tasks[0].Result + tasks[1].Result;
           Console.WriteLine("The answer is {0}", answer);
       }
    );
    

    b)ネストされた/子タスク

    //StartNew - starts task immediately, parent ends whith child
    var parent = Task.Factory.StartNew
    (() => {
              var child = Task.Factory.StartNew(() =>
             {
             //...
             });
          },  
          TaskCreationOptions.AttachedToParent
    );
    
  4. したがって、システムスレッドはタスクから完全に隠されていますが、それでもタスクのコードは具体的なシステムスレッドで実行されます。システムスレッドはタスクのリソースであり、もちろん、タスクの並列実行の内部にはスレッドプールがあります。スレッドが新しいタスクを実行する方法には、さまざまな戦略があります。別の共有リソースTaskSchedulerがそれを気にします。TaskSchedulerが解決するいくつかの問題1)同じスレッドでタスクとその継続を実行することを好み、スイッチングコストを最小限に抑えます-別名インライン実行)2)開始された順序でタスクを実行することを好みます-別名PreferFairness 3)非アクティブなスレッド間でタスクをより効果的に分散します「タスクアクティビティの事前知識」に応じて-別名仕事を盗む。重要:一般に、「非同期」は「並列」と同じではありません。TaskSchedulerオプションを使用すると、非同期タスクを1つのスレッドで同期的に実行するように設定できます。並列コード実行を表現するには、(タスクよりも)高度な抽象化を使用できます:Parallel.ForEach、、。PLINQDataflow

  5. タスクはC#async / await機能(別名Promise Model )と統合されています。たとえばrequestButton.Clicked += async (o, e) => ProcessResponce(await client.RequestAsync(e.ResourceName));、実行するclient.RequestAsyncとUIスレッドがブロックされません。重要:内部では、Clickedデリゲート呼び出しは完全に定期的です(すべてのスレッド化はコンパイラーによって行われます)。

それは選択をするのに十分です。ハングする傾向のあるレガシーAPIの呼び出しのキャンセル機能(タイムアウトレス接続など)をサポートする必要があり、この場合はThread.Abort()をサポートする場合、またはマルチスレッドバックグラウンド計算を作成していて、Suspend/Resumeを使用してスレッド間の切り替えを最適化する場合、つまり、並列実行を手動で管理することを意味します-スレッドにとどまります。それ以外の場合は、タスクに移動します。タスクのグループを簡単に操作でき、言語に統合され、開発者の生産性が向上します-タスク並列ライブラリ(TPL)

于 2013-02-13T12:30:10.037 に答える
40

このThreadクラスは、Windowsでスレッドを作成および操作するために使用されます。

ATaskは非同期操作を表し、タスクを非同期および並列で実行するためのAPIのセットであるタスク並列ライブラリの一部です。

昔(つまりTPL以前)は、Threadクラスを使用することがバックグラウンドまたは並列でコードを実行する標準的な方法の1つでしたが(より良い代替手段は多くの場合、を使用することでしたThreadPool)、これは面倒であり、いくつかの欠点があります。特に、バックグラウンドでタスクを実行するためのまったく新しいスレッドを作成することによるパフォーマンスのオーバーヘッドがあります。

現在、タスクとTPLを使用することは、システムリソースのはるかに効率的な使用を可能にする抽象化を提供するため、90%の確率ではるかに優れたソリューションです。コードを実行しているスレッドを明示的に制御したいシナリオがいくつかあると思いますが、一般的に、非同期で何かを実行したい場合は、最初の呼び出しポートをTPLにする必要があります。

于 2014-03-27T19:12:45.307 に答える