C++ Workflow中有五种基础任务:通讯、计算、文件IO、定时器、计数器,在coke项目中也分别对应着一组基础组件。在前面的文章中,我们已经分享过通讯任务(以HTTP为例)、通过coke::go发起计算任务,本文主要分享一下定时器任务的使用方法。细心的读者心想:我在前面的文章看到好几次coke::sleep了,作者又来水文章了。没错,定时器任务如此简单直接,现在再不分享,以后拿出来说更显得水文章了。

目前,coke提供了两个与定时器有关的接口,一个使用秒和纳秒作为参数,一个使用C++std::chrono::duration作为参数,使用示例如下

coke::Task<> test_sleep() {
    std::cout << "Sleep 1 sec and 10000 nsec\n";
    co_await coke::sleep(1, 10000);

    std::cout << "Sleep 1 sec\n";
    co_await coke::sleep(std::chrono::seconds(1));

    std::cout << "Sleep 1 sec and 20 msec\n";
    co_await coke::sleep(std::chrono::seconds(1) + std::chrono::milliseconds(20));

    std::cout << "Sleep 30 msec and 500 usec\n";
    co_await coke::sleep(std::chrono::milliseconds(30) + std::chrono::microseconds(500));
}

这则示例简洁直观,这里不再多余地文字描述。定时器任务的一个特性是一定会将当前协程挂起,即使指定的时间是0纳秒,也会让出执行权限,并由调度器重新调度任务。在coke中可以使用co_await coke::yield();作为co_await coke::sleep(0, 0);的语义上更有趣的语法糖。在某些特殊场景下,主动让出执行权限可以避免协程一直在占用同一个线程。一般情况下用户无需关心细节,只需在真正遇到问题时知道有这种机制可以解决问题即可,故本文不再赘述。

在实际应用中,我们常会遇到需要限制某类请求的Qps的需求,以避免将后台服务打挂引发服务故障等问题。对需求简单地分析可以发现,只需要在发起请求前等待一段时间,让每个请求都以一定的间隔均匀地发出即可,有了定时器这个组件,这个功能便可以很容易地实现。coke中已经提供了名为coke::QpsPool的组件来实现这个需求,下面通过一个例子来介绍一下使用方法

#include <iostream>
#include <chrono>
#include "coke/coke.h"

long long current_ms() {
    auto now = std::chrono::system_clock::now();
    return now.time_since_epoch().count() / 1000000LL;
}

coke::Task<> hello(coke::QpsPool &pool, int n) {
    for (int i = 0; i < n; i++) {
        co_await pool.get();
        std::cout << current_ms() << " hello world" << std::endl;

        if (i == 10)
            pool.reset_qps(2);
    }
}

int main() {
    coke::QpsPool qps_pool(5);
    coke::sync_wait(hello(qps_pool, 20));
    return 0;
}

在创建coke::QpsPool对象时需要指定一个qps值,每次进行需要限制qps的操作时(这里以向终端输出hello world为例),只需要co_await pool.get();即可,在正常使用期间,可以随时修改默认的qps值,下次进行get()操作时即可生效。示例中展示了当前毫秒时间戳,可非常方便地查看实际效果。

coke::QpsPool可在多个协程中同时使用,且重置qps的操作也是多线程安全的,例如可以单独启动一个线程或协程来监听外部事件,当发生某些情况时可以立刻重置qps值,以紧急应对特殊的需求。当然,限制qps只是个简单的君子协定,具体的业务还需具体分析,做出符合实际的合理的规划。

本系列文章同步发布于个人网站知乎专栏,转载请注明来源,以便读者及时获取最新内容及勘误。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注