Workflow 一切皆是Task

Workflow是搜狗近日开源的一款C++后端异步引擎,性能强劲。本文介绍Workflow的一项重要理念:Task。

一切皆是Task

在Workflow的编程范式中,一切可以独立完成某项任务的、边界清晰明确的代码模块,都可以抽象为一个Task。 Task之间可以互相组合,从而可以由简单Task构建出复杂Task。 从Client-Server的角度来看,无论是作为客户端还是服务器,Task理念都能很好地抽象实际情况。

Client请求是Task

使用Workflow作为Client,十分方便。 例如,创建一个HTTP请求,可以这么写:

std::function<void(WFHttpTask *)> http_callback;

auto *task = WFTaskFactory::create_http_task("http://www.sogou.com", 1, 3, http_callback);

task->start();

这条语句创建了一个对http://www.sogou.com的请求,允许1次重定向,最多可以重试3次,通信结束后自动调用callback即http_callback。 callback结束后Task执行完毕,自动销毁。 这个请求被包装为一个Task返回给用户,用户具体的操作都可以在这个Task上进行。

除了WFHttpTask,Workflow还内置了WFRedisTaskWFMySQLTaskWFKafkaTask等网络Task,以及可以用来创建线程任务的WFThreadTask、创建定时器的WFTimerTask、创建类似goroutine的WFGoTask、用于协调同步的WFCounterTask和构建有向无环图的WFGraphTask等丰富多彩的Task。 这些Task大多可以通过工厂类WFTaskFactory的静态方法创建。

Server处理对象也是Task

上面的程序片段已经展示了如何发起一个HTTP请求,下面的程序说明如何构建一个HTTP Server。

void process(WFHttpTask *task)
{
    task->get_resp()->append_output_body("<p>Hello</p>");
}

WFHttpServer server(process);
server.start(8080);

Workflow的理念是一切皆是Task,作为Server,也可以用Task的方式实现。 server.start(8080)之后,当有客户端对8080端口发起HTTP请求时, Workflow会生成一个Task,并调用void process(WFHttpTask *)来处理这个Task。 因此,用户只要在process中实现服务逻辑,即可构建出一个服务器。

复杂的服务器逻辑,很有可能需要Client Task的帮助, 比如一个代理服务器,收到Client的请求之后,需要向真实的Server发出请求,并将应答回复给Client, 这种Task之间的组合,正是Workflow擅长的地方。

Task间的相互组合

从Task的角度来看,重要的事情有两件:一是这个Task做什么,二是这个Task做完之后下一个Task是谁。 对于后一个问题,Workflow提供了多种Task间的组合方式。

串并联

auto *parallel = Workflow::create_parallel_work(nullptr);

auto *t1 = WFTaskFactory::create_http_task("http://www.sogou.com", 1, 3, nullptr);
auto *t2 = WFTaskFactory::create_go_task("A", some_function_A);
auto *t3 = WFTaskFactory::create_go_task("B", some_function_B;
auto *t4 = WFTaskFactory::create_redis_task("redis://127.0.0.1:6379/1", 3, nullptr);

parallel->add_series(Workflow::create_series_work(t2, nullptr));
parallel->add_series(Workflow::create_series_work(t3, nullptr));

auto *series = Workflow::create_series_work(t1, nullptr);
series->push_back(parallel);
series->push_back(t4);

series->start();

上面的代码,实现了下图中的先后次序。 当t1的callback执行结束时,t2t3将会开始执行;当t2t3的callback都执行结束时,t4将会开始执行。

          |--> t2 ---|
--> t1 ---|          |--> t4 ---
          |--> t3 ---|

这种串并联机制是十分朴素自然的组织方式,可以应对大多数简单的场景。 SeriesWork由Task串联组成,ParallelWorkSeriesWork并联组成,它们都可以设置callback。 同时,Workflow对于SereisWork和ParallelWork进行了一定的约束:

  • SeriesWork由若干Task串联而成,任何运行中的Task都属于某个SeriesWork;
  • ParallelWork由若干SeriesWork并联而成;
  • ParallelWork是一种Task。

之所以有此约束,是为了防止滥用串并联而带来的复杂性。

动态地串并联

串并联除了可以静态地组装,也可以动态地在callback中修改。 例如:

auto *t1 = WFTaskFactory::create_http_task("http://www.sogou.com", 1, 3, [](WFHttpTask * task){
    auto *t2 = WFTaskFactory::create_go_task("", [](){});
    auto *series = series_of(task);
    series->push_back(t2);
});

t1->start();

由于Task必然是某个SeriesWork的一环(即使没有显式创建此SeriesWork),因此可以在Task的callback中拿到这个SeriesWork,向其添加新的Task。 需要注意的是,无法通过类似的方法向ParallelWork中添加新的SeriesWork,因为: 第一,并非所有的SeriesWork都是某个ParallelWork的一支; 第二,ParallelWork会同时启动它包含的所有SeriesWork,之后再次试图添加,是违反语义的。

总结

Workflow的Task理念是一种完备的编程方法,巧妙地将各种异步过程结合起来,方便用户使用。 Workflow还有其它有趣的特色,后面会继续介绍。 在Workflow的主页上,也有十分详细的进一步的文档介绍,欢迎各位访问。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值