TBB中图的类型

一、图的基本类型

在前面对图(Graph)进行了基础的分析说明并给了简单的应用。现在回过头来看,图在TBB框架中的重要性已经有了深刻的体验。在了解了图的工作原理后,就会发现,在TBB中的图,其实并不是简单的进行数据流控制那么简单。一般来说,在TBB中主流的图可以划分成两大类:
1、数据流图
数据流图其实就是前面分析过的。数据沿着图的边向相连接的节点进行传递,节点进行消息的接收、处理和转发。
2、依赖图
在这种图中,与数据流图不同的在于,节点获取数据的方式是通过共享内存实现的而非通过边传递。而在此类图中,边更意味着是一种限制或者说前置条件(依赖关系的说明)。

二、数据流图

数据流图介绍了很多次,就不再赘述,只把官网的例子拿上来:

int sum = 0;
graph g;
function_node< int, int > squarer( g, unlimited, [](const int &v) {
    return v*v;
} );
function_node< int, int > cuber( g, unlimited, [](const int &v) {
    return v*v*v;
} );
function_node< int, int > summer( g, 1, [&](const int &v ) -> int {
    return sum += v;
} );
make_edge( squarer, summer );
make_edge( cuber, summer );


for ( int i = 1; i <= 10; ++i ) {
  squarer.try_put(i);
  cuber.try_put(i);
}
g.wait_for_all();


cout << "Sum is " << sum << "\n";

数据流图的优点在于它可以在复杂的应用场景下使用,它更容易为计算流程所使用。或者说在数据驱动型的计算框架中,使用更积极。

三、依赖图

谈到依赖图,其实学过“离散数学”或者进行UML设计的开发者可能更容易理解。依赖其实非常容易,就是一种条件的限制。比如多线程里的栅栏、条件变量等等。而体现在图中,就是一个逻辑关系图:
在这里插入图片描述

这个图有点麻烦,可以更清晰的画成下面的图:
在这里插入图片描述

看一下代码:

#include <algorithm>
#include <execution>
#include <iostream>
#include <random>
#include <vector>
#include <tbb/tbb.h>
#include <tbb/flow_graph.h>

typedef tbb::flow::continue_node<tbb::flow::continue_msg> node_t;
typedef const tbb::flow::continue_msg & msg_t;

void a(){std::cout<<"exec a func!"<<std::endl;}
void b(){std::cout<<"exec b func!"<<std::endl;}
void c(){std::cout<<"exec c func!"<<std::endl;}
void d(){std::cout<<"exec d func!"<<std::endl;}
void e(){std::cout<<"exec e func!"<<std::endl;}
void f(){std::cout<<"exec f func!"<<std::endl;}
int main() {
  tbb::flow::graph g;
  node_t A(g, [](msg_t){ a(); } );
  node_t B(g, [](msg_t){ b(); } );
  node_t C(g, [](msg_t){ c(); } );
  node_t D(g, [](msg_t){ d(); } );
  node_t E(g, [](msg_t){ e(); } );
  node_t F(g, [](msg_t){ f(); } );
  make_edge(A, B);
  make_edge(B, C);
  make_edge(B, D);
  make_edge(A, E);
  make_edge(E, D);
  make_edge(E, F);
  A.try_put( tbb::flow::continue_msg() );
  g.wait_for_all();
  return 0;
}

编译:

g++ -O2 -DNDEBUG  -o tbb_dep tbb_dep.cpp -ltbb -lrt -std=c++17
#如存在多版本,请指定:
 g++ -O2 -DNDEBUG -I /usr/local/include -L /usr/local/lib -o tbb3 tbb3.cpp -ltbb -lrt -std=c++17

运行结果:

exec a func!
exec e func!
exec f func!
exec b func!
exec d func!
exec c func!

这和设定的A先执行,然后B和E才允许执行,依次是F、D和C。但在B和E间以及其下的C、D和F却没有明确的定义执行顺序。而程序整体是异步的,所以大家应该明白会是一个什么情况。或者这样理解,后继节点只有发现其所有的前驱节点均已完成时,才会执行。
其实大家在看到代码前就应该想到,它一定是有一类专门的节点和消息来处理这种类型的图。比如上面代码中continue_msg和continue_node。continue_node在TBB中被视为无限并发的节点,只要有条件满足就会生成任务执行(当然前提仍然是真正有执行的线程或执行单元)。上面的代码可以视为下面的图的执行顺序过程:

在这里插入图片描述

单纯从图上理解,有一点递推的意思。如果用程序代码来说,有点条件满足才会执行的味道。

四、总结

纸上学来终觉浅啊,还是要亲自跑一下代码。实践和理论一起向前推进,才能更好的理解相关的程序代码和其内在的运行机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值