进行多次异步调用并在完成后执行某些操作

时间:2009-06-24 15:10:45

标签: asynchronous coding-style

我在多种编程语言中遇到过这个问题,我只是想知道处理它的最佳方法是什么。

我有三个异步触发的方法调用。每个人都有一个回调。我想只在完成所有三个回调时才做某事。

对此进行编码的最佳方法是什么?我通常最终得到所有这些公共bool标志,当你添加更多调用时,代码会变得更复杂。

5 个答案:

答案 0 :(得分:3)

来自C#,我可能会使用WaitHandle.WaitAll。您可以创建一个ManualResetEvent对象数组(每个要完成的任务一个),并将该数组传递给WaitAll。线程任务将分别获得一个ManualResetEvent对象,并在准备好时调用Set方法。 WaitAll将阻止调用线程,直到完成所有任务。我将给出一个C#代码示例:

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();
}

请注意,AllTasksAreDone方法将在用于生成worker的线程池线程上执行,而不是在主线程上执行...我假设许多其他语言具有类似的结构。

答案 1 :(得分:1)

如果您真的只想等待所有完成:

  1. 创建易失性计数器
  2. 同步访问计数器
  3. 开始时增加计数器
  4. 减少回拨“
  5. 等待计数器达到0

答案 2 :(得分:0)

使用semaphore

答案 3 :(得分:0)

期货很容易使用。期货看起来像普通函数,除了它们执行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;
    }
}

在这里,我使用期货来模拟死锁:

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;
    }
}

答案 4 :(得分:0)

对于那些使用JavaScript的人,请考虑使用此Stackoverflow问题中讨论的模式: javascript: execute a bunch of asynchronous method with one callback