多个异步操作完成后运行回调

时间:2011-01-04 11:36:37

标签: c# asynchronous c#-4.0 callback

我有 asynchrounous 函数接受回调

void requestSomething (Action callback)

我需要多次运行它并在所有功能完成后运行MainCallback

for (int i=0;i<5;i++)
   requestSomething (singleCallback);

我想如何使用计数器计算5次,然后运行mainCallback,但我相信有更好的方法可以做到这一点。

编辑:

我可以这样做:

int counter = 5;

for (int i=0;i<counter;i++)
{
       requestSomething (()=> { counter--;
                                  if (counter == 0)
                                     mainCallback()} );
}

有没有更好的方法来实现这个逻辑?

3 个答案:

答案 0 :(得分:1)

这是一个简单的程序,它演示了如何使用任务并行库来调用异步函数并等待所有人完成继续。然后,您可以调整代码以执行相同的操作。

class Program
{
    static void Main(string[] args)
    {
        var asyncFunc = new Action<int>(i =>
            {
                Thread.Sleep((i+1) * 1000);
                Console.WriteLine("Called {0}!", i);
            });
        var callback = new Action(() => Console.WriteLine("Callback called"));
        var requests = Enumerable.Range(0, 5)
                                 .Select(i =>
                                  {
                                      return Task.Factory
                                                  // wrap asynchronous call in a task
                                                 .FromAsync(asyncFunc.BeginInvoke, asyncFunc.EndInvoke, i, asyncFunc)
                                                  // register callback
                                                 .ContinueWith(_ => callback());
                                  })
                                 .ToArray();
        Task.WaitAll(requests);
        // do callback
        Console.WriteLine("All called!");
        Console.Write("Press any key to continue . . . ");
        Console.ReadKey(true);
        Console.WriteLine();
    }
}

如果没有看到你的异步函数是如何实现的,我只能假设你需要更改它以将异步调用作为任务返回以使其工作。可能这样的事情对你有用:

Task requestSomething(Action callback)
{
    // do stuff...
    return Task.Factory
               .FromAsync(obj.BeginInvoke,
                          obj.EndInvoke,
                          ..., // async func arguments
                          obj)
               .ContinueWith(_ => callback());
}

// usage:
var tasks = Enumerable.Range(0, 5)
                      .Select(_ => requestSomething(singleCallback))
                      .ToArray();
Task.WaitAll(tasks);
mainCallback();

答案 1 :(得分:1)

您可以在类中封装回调和计数器:

实施例

public class CallbackCounter
{
    protected Int32 Counter { get; set; }        
    public Int32 MaxCount { get; set; }
    public Action Action { get; set; }

    public event EventHandler FinalCallback;

    public CallbackCounter(Action action, Int32 maxCount)
    {
        Action = action;
        Counter = 0;
        MaxCount = maxCount;
    }

    public void Callback()
    {
        Action();
        Counter++;
        if (Counter >= MaxCount)
            RaiseFinalCallback();
    }

    private void RaiseFinalCallback()
    {
        EventHandler temp = FinalCallback;
        if (temp != null)
        {
            temp(this, EventArgs.Empty);
        }
    }
} 

使用如下:

CallbackCounter cc = new CallbackCounter(singleCallback, 5);

cc.FinalCallback += (sender, e) => { 
    // Final callback
};

for (int i = 0; i < 5; i++)
    requestSomething(cc.Callback);

答案 2 :(得分:0)

我认为你将不得不使用线程安全计数(即使用LOCK),你在回调时递增,然后检查回调方法入口点的值,以确保预期的方法数量已经完成。 / p>