私はこの問題を複数のプログラミング言語で実行しましたが、私はそれを処理する最良の方法が何であるか不思議でした。複数の非同期呼び出しを行い、完了したら何かを実行します
私は非同期的に起動する3つのメソッド呼び出しを持っています。それぞれにコールバックがあります。 3つのコールバックがすべて完了したときにだけ何かしたい。
これをコードする最良の方法は何ですか?私は通常、これらのパブリックブールフラグをすべて終了し、コールを追加するとコードがより複雑になります。
私はこの問題を複数のプログラミング言語で実行しましたが、私はそれを処理する最良の方法が何であるか不思議でした。複数の非同期呼び出しを行い、完了したら何かを実行します
私は非同期的に起動する3つのメソッド呼び出しを持っています。それぞれにコールバックがあります。 3つのコールバックがすべて完了したときにだけ何かしたい。
これをコードする最良の方法は何ですか?私は通常、これらのパブリックブールフラグをすべて終了し、コールを追加するとコードがより複雑になります。
C#からは、おそらくWaitHandle.WaitAll
が使用されます。 ManualResetEvent
オブジェクトの配列を作成し(完了する各タスクに1つずつ)、配列をWaitAll
に渡すことができます。スレッド化されたタスクは、それぞれ1つのManualResetEventオブジェクトを取得し、準備ができたらSet
メソッドを呼び出します。 WaitAll
は、すべてのタスクが完了するまで呼び出しスレッドをブロックします。私はC#のコード例をあげる:AllTasksAreDone
方法は、メインスレッド上で労働者を起動するために使用されたスレッドプールのスレッドで実行し、ないことを
private void SpawnWorkers()
{
ManualResetEvent[] resetEvents = new[] {
new ManualResetEvent(false),
new ManualResetEvent(false)
};
// spawn the workers from a separate thread, so that
// the WaitAll call does not block the main thread
ThreadPool.QueueUserWorkItem((state) =>
{
ThreadPool.QueueUserWorkItem(Worker1, resetEvents[0]);
ThreadPool.QueueUserWorkItem(Worker2, resetEvents[1]);
WaitHandle.WaitAll(resetEvents);
this.BeginInvoke(new Action(AllTasksAreDone));
});
}
private void AllTasksAreDone()
{
// OK, all are done, act accordingly
}
private void Worker1(object state)
{
// do work, and then signal the waiting thread
((ManualResetEvent) state).Set();
}
private void Worker2(object state)
{
// do work, and then signal the waiting thread
((ManualResetEvent)state).Set();
}
注意を...私は他の多くのことを前提としてい言語は同様の構造を持っています。
あなたが本当に唯一終了するのすべてのを待ちたい場合:
semaphoreを使用してください。
先物は非常に使いやすいです。先物は通常の機能と似ていますが、asynchを実行する点が異なります。
クラス:
public struct FutureResult<T>
{
public T Value;
public Exception Error;
}
public class Future<T>
{
public delegate R FutureDelegate<R>();
public Future(FutureDelegate<T> del)
{
_del = del;
_result = del.BeginInvoke(null, null);
}
private FutureDelegate<T> _del;
private IAsyncResult _result;
private T _persistedValue;
private bool _hasValue = false;
private T Value
{
get
{
if (!_hasValue)
{
if (!_result.IsCompleted)
_result.AsyncWaitHandle.WaitOne();
_persistedValue = _del.EndInvoke(_result);
_hasValue = true;
}
return _persistedValue;
}
}
public static implicit operator T(Future<T> f)
{
return f.Value;
}
}
ここで私はデッドロックをシミュレートするために先物を使用します。JavaScriptを使用してそれらのために
void SimulateDeadlock()
{
Future> deadlockFuture1 = new Future>(() =>
{
try
{
new SystemData(ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)
.SimulateDeadlock1(new DateTime(2000, 1, 1, 0, 0, 2));
return new FutureResult { Value = true };
}
catch (Exception ex)
{
return new FutureResult { Value = false, Error = ex };
}
});
Future> deadlockFuture2 = new Future>(() =>
{
try
{
new SystemData(ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)
.SimulateDeadlock2(new DateTime(2000, 1, 1, 0, 0, 2));
return new FutureResult { Value = true };
}
catch (Exception ex)
{
return new FutureResult { Value = false, Error = ex };
}
});
FutureResult result1 = deadlockFuture1;
FutureResult result2 = deadlockFuture2;
if (result1.Error != null)
{
if (result1.Error is SqlException && ((SqlException)result1.Error).Number == 1205)
Console.WriteLine("Deadlock!");
else
Console.WriteLine(result1.Error.ToString());
}
else if (result2.Error != null)
{
if (result2.Error is SqlException && ((SqlException)result2.Error).Number == 1205)
Console.WriteLine("Deadlock!");
else
Console.WriteLine(result2.Error.ToString());
}
}
いくつかのクラスがこの例から抜けています – mcintyre321
、このstackoverflowの質問で述べたパターンを使用することを検討してください: javascript: execute a bunch of asynchronous method with one callback
this.BeginInvokeを呼び出すとき?これは何ですか'? –