49

2 つの独立したロジックを実行するメソッドがあります。両方を同時に実行できることを望んでいました..そして、それらの子メソッドが両方とも完了したときにのみ続行します。

構文を理解しようとしましたが、async/awaitわかりません。

コードは次のとおりです。

public PewPew SomeMethod(Foo foo)
{
    var cats = GetAllTheCats(foo);
    var food = GetAllTheFood(foo);

    return new PewPew
               {
                   Cats = cats,
                   Food = food
               };
}

private IList<Cat> GetAllTheCats(Foo foo)
{
    // Do stuff, like hit the Db, spin around, dance, jump, etc...
    // It all takes some time.
    return cats;
}

private IList<Food> GetAllTheFood(Foo foo)
{
    // Do more stuff, like hit the Db, nom nom noms...
    // It all takes some time.
    return food;
}

上記のコードで、私が言いたいのは、すべての猫と食べ物を同時に手に入れようということです。終了したら、 new を返しますPewPew

async上記のどのクラスがa などを返すかわからないため、混乱していますTask。すべての em ですか? プライベートの2つだけ?また、この方法を活用する必要があると推測していますが、タスクを同時に実行するように設定Task.WaitAll(tasks)する方法がわかりません。

提案、親切な人々?

4

5 に答える 5

63

やりたいことは次のとおりです。

public async Task<PewPew> SomeMethod(Foo foo)
{
    // get the stuff on another thread 
    var cTask = Task.Run(() => GetAllTheCats(foo));
    var fTask = Task.Run(() => GetAllTheFood(foo));

    var cats = await cTask;
    var food = await fTask;

    return new PewPew
               {
                   Cats = cats,
                   Food = food
               };
}

public IList<Cat> GetAllTheCats(Foo foo)
{
    // Do stuff, like hit the Db, spin around, dance, jump, etc...
    // It all takes some time.
    return cats;
}

public IList<Food> GetAllTheFood(Foo foo)
{
    // Do more stuff, like hit the Db, nom nom noms...
    // It all takes some time.
    return food;
}

ここで理解しなければならないことが 2 つあります。

1)これの違いは何ですか:

var cats = await cTask;
var food = await fTask;

この:

Task.WaitAll(new [] {cTask, fTask});

asyncどちらも、2 つのタスクを終了させるという意味で同様の結果をもたらしますreturn new PewPewが、違いはTask.WaitAll()現在のスレッドをブロックすることです (それが UI スレッドの場合、UI はフリーズします)。代わりに、ステート マシンで発言awaitを分解し、キーワードに遭遇すると から呼び出し元に戻ります。スレッドをブロックしません。以下のコードは、タスクが終了したときに実行されるようにスケジュールされます。SomeMethodSomeMethodawaitawaitasync

2)これを行うこともできます:

var cats = await Task.Run(() => GetAllTheCats(foo));
var food = await Task.Run(() => GetAllTheFood(foo));

ただし、これはasyncタスクを同時に開始しません。最初のタスクが終了すると、2 番目のタスクが開始されます。これは、awaitキーワードがどのように機能するかによるものです。お役に立てば幸いです...

編集: 使用方法SomeMethod- コール ツリーの先頭のどこかで、Wait()またはResultプロパティを使用する必要があります - または - awaitfromを使用する必要がありますasync void。通常、async voidイベント ハンドラーになります。

public async void OnSomeEvent(object sender, EventArgs ez) 
{ 
  Foo f = GetFoo();
  PewPew p = await SomeMethod(f);
}

そうでない場合は、Resultプロパティを使用します。

public Foo2 NonAsyncNonVoidMethod() 
{
   Foo f = GetFoo();
   PewPew p = SomeMethod(f).Result; //But be aware that Result will block thread

   return GetFoo2(p);
}
于 2013-05-24T06:15:19.850 に答える
28

これを行う最も簡単な方法は、Parallel.Invoke()

IList<Cat> cats;
IList<Food> food;

Parallel.Invoke
(
    () => cats = GetAllTheCats(foo),
    () => food = GetAllTheFood(foo)
);

Parallel.Invoke()それ自体が戻る前に、すべてのメソッドが戻るのを待ちます。

詳細はこちら: http://msdn.microsoft.com/en-us/library/dd460705.aspx

Parallel.Invoke()システム内のプロセッサ数へのスケーリングを処理することに注意してください。

于 2013-05-24T06:18:35.817 に答える
12

非同期メソッドを使用していない場合、または古いバージョンの .Net フレームワークを使用している場合は、非同期を使用する必要はありません。簡単にするためにタスクを使用するだけです。

Task taskA = Task.Factory.StartNew(() => GetAllTheCats(foo));
Task taskB = Task.Factory.StartNew(() => GetAllTheFood(foo));

Task.WaitAll(new [] { taskA, taskB });
// Will continue after both tasks completed
于 2013-05-24T06:08:19.987 に答える
1

TPLを使用して、実行中の複数のタスクを待機できます。ここを参照してください。

このような:

public PewPew SomeMethod(Foo foo) {
    IList<Cat> cats = null;
    IList<Food> foods = null;

    Task[] tasks = new tasks[2] {
        Task.Factory.StartNew(() => { cats = GetAllTheCats(foo); }),
        Task.Factory.StartNew(() => { food = GetAllTheFood(foo); })
    };

    Task.WaitAll(tasks);

    return new PewPew
               {
                   Cats = cats,
                   Food = food
               };
}
于 2013-05-24T06:09:50.237 に答える