私は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;
}
_
したがって、上記のコードでは、すべての猫と餌を同時に手に入れてください。終了したら、新しいPewPew
を返します。
上記のどのクラスがasync
なのか、Task
などを返すのかわからないため、混乱しています。プライベートな2つだけですか?私はTask.WaitAll(tasks)
メソッドを活用する必要があると推測していますが、同時に実行するタスクをsetupする方法がわかりません。
提案、親切な人?
あなたがしたいことがあるかもしれません:
_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});
_
どちらも2つのasync
タスクを終了させてから_return new PewPew
_をさせるという意味で同様の結果をもたらします-ただし、違いはTask.WaitAll()
が現在のスレッドをブロックすることです(UIの場合スレッド、UIがフリーズします)。代わりに、await
は、ステートマシンでSomeMethod
sayを分解し、SomeMethod
キーワードに遭遇すると、await
から呼び出し元に戻ります。スレッドをブロックしません。以下のコードawait
は、async
タスクが終了したときに実行されるようにスケジュールされます。
2)これもできます:
_var cats = await Task.Run(() => GetAllTheCats(foo));
var food = await Task.Run(() => GetAllTheFood(foo));
_
ただし、これはasync
タスクを同時に開始しません。最初のタスクが終了すると、2番目のタスクが開始されます。これは、await
キーワードがどのように機能するかということです。
編集:SomeMethod
の使用方法-呼び出しツリーの先頭のどこかで、Wait()
またはResult
プロパティを使用する必要があります-OR =-_async void
_からawait
にする必要があります。通常、_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);
}
_
これを行う最も簡単な方法は、 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()
はシステム内のプロセッサの数に応じてスケーリングを処理しますが、それは実際に重要なのは、2つ以上のタスクを開始する場合のみです。
非同期メソッドを使用していない場合、または.Netフレームワークの古いバージョンを使用している場合は、非同期を使用する必要はありません。Tasks 簡単にするために:
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
[〜#〜] tpl [〜#〜] を使用して、実行中に複数のタスクを待つことができます。 here を参照してください。
このような:
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
};
}
他の答えに追加すると、次のようなことができます:
public PewPew SomeMethod(Foo foo)
{
Task<IList<Cat>> catsTask = GetAllTheCatsAsync(foo);
Task<IList<Food>> foodTask = GetAllTheFoodAsync(foo);
// wait for both tasks to complete
Task.WaitAll(catsTask, foodTask);
return new PewPew
{
Cats = catsTask.Result,
Food = foodTask.Result
};
}
public async Task<IList<Cat>> GetAllTheCatsAsync(Foo foo)
{
await Task.Delay(7000); // wait for a while
return new List<Cat>();
}
public async Task<IList<Food>> GetAllTheFoodAsync(Foo foo)
{
await Task.Delay(5000); // wait for a while
return new List<Food>();
}