You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何统计带回调的多异步函数调用总执行耗时?

异步方法批量调用的总执行耗时统计方案

同步方法的耗时统计(参考示例)

当DoWork()是同步方法时,统计n次调用的总耗时非常直接,只需在循环前后记录时间即可:

// File: PrepareForWork.cpp
Timer startTime = GetCurrentTime();
for (int i = 0; i < n; i++)
{
    workerObj->DoWork();
}
cout << "Total execution time: " << GetCurrentTime() - startTime << endl;
// File: Worker.cpp
Worker::DoWork()
{
    // 执行具体任务逻辑
}

异步方法的统计难点

当方法改为带完成回调CallBackOnComplete()的异步方法DoWorkAsync()时,任务执行与回调逻辑分散在不同文件,且异步任务是并发执行的——循环会立刻结束,但此时所有异步任务可能仍在运行,无法直接用同步方式统计总耗时。

原异步示例代码:

// File: PrepareForWork.cpp
for (int i = 0; i < n; i++)
{
    workerObj->DoWorkAsync();
}
// File: Worker.cpp
Worker::DoWorkAsync()
{
    // 触发异步任务执行
}

Worker::CallBackOnComplete(Data* outputData)
{
    // 任务完成后的回调逻辑
}

可行解决方案

方案1:线程安全计数器+共享计时器

核心逻辑:在发起异步任务前记录起始时间,用线程安全的计数器跟踪已完成任务数,当最后一个任务的回调触发时,计算总耗时。

修改后代码实现

  1. PrepareForWork.cpp
#include <atomic>

std::atomic<int> completedTasks = 0;
Timer globalStartTime;

int main()
{
    int n = 10; // 示例调用次数
    globalStartTime = GetCurrentTime();

    for (int i = 0; i < n; i++)
    {
        workerObj->DoWorkAsync();
    }

    // 实际项目建议用条件变量替代空循环,避免CPU空转
    while (completedTasks < n) {}

    cout << "Total execution time: " << GetCurrentTime() - globalStartTime << endl;
    return 0;
}
  1. Worker.cpp
#include "PrepareForWork.h" // 引入计数器与起始时间的声明

Worker::CallBackOnComplete(Data* outputData)
{
    // 原有回调逻辑
    // ...

    int completed = ++completedTasks;
    // 最后一个任务完成时计算总耗时
    if (completed == n) // n需保证跨文件可见(比如全局常量或传递参数)
    {
        cout << "Total execution time (callback): " << GetCurrentTime() - globalStartTime << endl;
    }
}

方案2:传递任务上下文(更优雅的封装)

避免全局变量,给每个异步任务传递包含起始时间、总任务数、完成计数器的上下文对象,在回调中统一统计。

修改后代码实现

  1. 公共头文件定义上下文结构体
#include <atomic>

struct TaskContext
{
    Timer startTime;
    int totalTasks;
    std::atomic<int>* completedCount;
};
  1. PrepareForWork.cpp
int main()
{
    int n = 10;
    std::atomic<int> completedCount = 0;
    Timer startTime = GetCurrentTime();

    TaskContext ctx{startTime, n, &completedCount};

    for (int i = 0; i < n; i++)
    {
        workerObj->DoWorkAsync(&ctx);
    }

    while (completedCount < n) {}

    cout << "Total execution time: " << GetCurrentTime() - startTime << endl;
    return 0;
}
  1. Worker.cpp
Worker::DoWorkAsync(TaskContext* ctx)
{
    // 触发异步任务时携带上下文,确保回调能获取到
    startAsyncTask([ctx](Data* data) {
        CallBackOnComplete(data, ctx);
    });
}

Worker::CallBackOnComplete(Data* outputData, TaskContext* ctx)
{
    // 原有回调逻辑
    // ...

    int completed = ++(*ctx->completedCount);
    if (completed == ctx->totalTasks)
    {
        cout << "Total execution time: " << GetCurrentTime() - ctx->startTime << endl;
    }
}

注意事项

  • 必须用线程安全的计数器(如std::atomic),因为回调可能在不同线程触发。
  • 主线程的等待逻辑,实际项目中推荐用std::condition_variable替代空循环,避免不必要的CPU消耗。
  • 需确保上下文对象的生命周期覆盖所有异步任务的回调执行周期,避免野指针问题。

内容的提问来源于stack exchange,提问作者ontherocks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 23:00:20