matrix_multiply代码解析
matrix_multiply代码解析
关于matrix_multiply
程序执行代码里两个矩阵的乘法,并将相乘结果打印在屏幕上。
示例的主要目的是展现怎么实现一个自定义CPU计算任务。
参考:https://github.com/sogou/workflow
示例代码
https://github.com/sogou/workflow/blob/master/tutorial/tutorial-08-matrix_multiply.cc
定义计算任务
定义计算任务需要提供3个基本信息,分别为INPUT,OUTPUT,和routine。
INPUT和OUTPUT是两个模板参数,可以是任何类型。routine表示从INPUT到OUTPUT的过程,定义如下:
template <class INPUT, class OUTPUT>
class __WFThreadTask
{
...
std::function<void (INPUT *,
OUTPUT *)> routine;
...
};
可以看出routine是一个简单的从INPUT到OUTPUT的计算过程。INPUT指针不要求是const,但用户也可以传const INPUT *的函数。
比如一个加法任务,就可这么做:
struct add_input
{
int x;
int y;
};
struct add_ouput
{
int res;
};
void add_routine(const add_input
*input, add_output *output)
{
output->res = input->x + input->y;
}
typedef
WFThreadTask<add_input, add_output> add_task;
在矩阵乘法的示例里,输入是两个矩阵,输出为一个矩阵。其定义如下:
namespace algorithm
{
using Matrix =
std::vector<std::vector<double>>;
struct MMInput
{
Matrix a;
Matrix b;
};
struct MMOutput
{
int error;
size_t m, n, k;
Matrix c;
};
void matrix_multiply(const MMInput *in,
MMOutput *out)
{
...
}
}
矩阵乘法存在有输入矩阵不合法的问题,所以output里多了一个error域,用来表示错误。
生成计算任务
定义好输入输出的类型,以及算法的过程之后,就可以通过WFThreadTaskFactory工厂来产生计算任务了。
在WFTaskFactory.h里,计算工厂类的定义如下:
template <class INPUT, class OUTPUT>
class WFThreadTaskFactory
{
private:
using T =
WFThreadTask<INPUT, OUTPUT>;
public:
static T *create_thread_task(const
std::string& queue_name,
std::function<void (INPUT *,
OUTPUT *)> routine,
std::function<void (T *)> callback);
...
};
与之前的网络工厂类或算法工厂类略有不同,这个类需要INPUT和OUTPUT两个模板参数。
queue_name相关的知识在上一个示例里已经有介绍。routine就是你的计算过程,callback是回调。
在示例里,看到了这个调用的使用:
using MMTask =
WFThreadTask<algorithm::MMInput,
algorithm::MMOutput>;
using namespace algorithm;
int main()
{
typedef
WFThreadTaskFactory<MMInput, MMOutput> MMFactory;
MMTask *task = MMFactory::create_thread_task("matrix_multiply_task",
matrix_multiply,
callback);
MMInput *input = task->get_input();
input->a = {{1, 2, 3}, {4, 5, 6}};
input->b = {{7, 8}, {9, 10}, {11, 12}};
...
}
产生了task之后,通过get_input()接口得到输入数据的指针。这个可以类比网络任务的get_req()。
任务的发起和结束什么,与网络任务并没有什么区别。同样,回调也很简单:
void callback(MMTask
*task) // MMtask =
WFThreadTask<MMInput, MMOutput>
{
MMInput *input = task->get_input();
MMOutput *output = task->get_output();
assert(task->get_state() ==
WFT_STATE_SUCCESS);
if (output->error)
printf("Error: %d
%s\n", output->error, strerror(output->error));
else
{
printf("Matrix A\n");
print_matrix(input->a,
output->m, output->k);
printf("Matrix B\n");
print_matrix(input->b,
output->k, output->n);
printf("Matrix A *
Matrix B =>\n");
print_matrix(output->c,
output->m, output->n);
}
}
普通的计算任务可以忽略失败的可能性,结束状态肯定是SUCCESS。
callback里简单打印了输入输出。如果输入数据不合法,则打印错误。
算法与协议的对称性
在体系里,算法与协议在一个非常抽象的层面上是具有高度对称性的。
有自定义算法的线程任务,那显然也存在自定义协议的网络任务。
自定义算法要求提供算法的过程,而自定义协议则需要用户提供序列化和反序列化的过程。
无论是自定义算法还是自定义协议,都必须强调算法和协议都是非常纯粹的。
例如算法就是一个从INPUT到OUPUT的转换过程,算法并不知道task,series等的存在。
HTTP协议的实现上,也只关心序列化反序列化,无需要关心什么是task。而是在http task里去引用HTTP协议。
线程任务与网络任务的复合性
在这个示例里,通过WFThreadTaskFactory构建了一个线程任务。可以说这是一种最简单的计算任务构建,大多数情况下也够用了。
同样,用户可以非常简单的定义一个自有协议的server和client。
但在上一个示例里看到,可以通过算法工厂产生一个并行排序任务,这显然不是通过一个routine就能做到的。
对于网络任务,比如一个kafka任务,可能要经过与多台机器的交互才能得到结果,但对用户来讲是完全透明的。
所以,任务都是具有复合性的,如果你熟练使用框架,可以设计出很多复杂的组件出来。
matrix_multiply代码解析的更多相关文章
- VBA常用代码解析
031 删除工作表中的空行 如果需要删除工作表中所有的空行,可以使用下面的代码. Sub DelBlankRow() DimrRow As Long DimLRow As Long Dimi As L ...
- [nRF51822] 12、基础实验代码解析大全 · 实验19 - PWM
一.PWM概述: PWM(Pulse Width Modulation):脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形. PWM 的几个基本概念: 1) 占空比:占空比是指 ...
- [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写
一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...
- [nRF51822] 10、基础实验代码解析大全 · 实验15 - RTC
一.实验内容: 配置NRF51822 的RTC0 的TICK 频率为8Hz,COMPARE0 匹配事件触发周期为3 秒,并使能了TICK 和COMPARE0 中断. TICK 中断中驱动指示灯D1 翻 ...
- [nRF51822] 9、基础实验代码解析大全 · 实验12 - ADC
一.本实验ADC 配置 分辨率:10 位. 输入通道:5,即使用输入通道AIN5 检测电位器的电压. ADC 基准电压:1.2V. 二.NRF51822 ADC 管脚分布 NRF51822 的ADC ...
- java集合框架之java HashMap代码解析
java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...
- Kakfa揭秘 Day8 DirectKafkaStream代码解析
Kakfa揭秘 Day8 DirectKafkaStream代码解析 今天让我们进入SparkStreaming,看一下其中重要的Kafka模块DirectStream的具体实现. 构造Stream ...
- linux内存管理--slab及其代码解析
Linux内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配,被称为slab高速缓存. 内存管理的目标是提供一种方法,为实 ...
- MYSQL常见出错mysql_errno()代码解析
如题,今天遇到怎么一个问题, 在理论上代码是不会有问题的,但是还是报了如上的错误,把sql打印出來放到DB中却可以正常执行.真是郁闷,在百度里面 渡 了很久没有相关的解释,到时找到几个没有人回复的 & ...
随机推荐
- CVE-2010-3974:Windows 传真封面编辑器 FxsCover.exe 双重释放漏洞调试分析
0x01 堆空间申请后的双重释放 Windows FxsCover 程序存储封面编辑器的信息,封面编辑器是传真服务的一个组件,通过解析特定的传真封面文件(.cov)时,会调用类析构函数对同一内存中的栈 ...
- 4.PHP正则表达式与数组
PHP正则表达式相关 行定位符 开头 ^tm 结尾 tm$ 不限制 tm 单词定界符 \btm\b 单词tm,如果想取反的话就是大写的 \Btm\B 或的关系,[Tt][Mm] 可以表达 tm T ...
- 逆向与分析-WebBrowserPassView消息分析
逆向与分析-WebBrowserPassView消息分析 这个的源头是之前我写的一个博客: http://blog.csdn.net/u013761036/article/details/730427 ...
- android The content of the adapter has changed but ListView did not receive a notification 错误的解决方案
使用了AsyncTask在后台刷新适配器,并且通知ui线程更新ListView,运行时发现时不时的出现 如题 的错误, 导致程序崩溃,解决方法如下: 1.建立一个缓冲数据集,这个数据集就是填充适配器的 ...
- Win10安装MySQL5和MySQL8
1. 下载数据库,配置环境变量 因为是安装两个MySQL数据库,端口号要不一样,MySQL默认端口号是3306,建议先配置非默认端口号,以免出现问题 1.1 官网下载5.7和8.0的压缩包 我下载的是 ...
- IO异步,读写压缩文件,监控文件系统
这节结尾IO,讲一下异步操作文件,读写压缩文件,监控文件系统这三个知识点. 异步操作文件: 说到异步,必然要了解的是async和await这两个关键字(异步详情点击基于任务的异步编程(Task ...
- Spring Boot 2.5.0 发布:支持Java16、Gradle 7、Datasource初始化机制调整
今年520的事情是真的多,娱乐圈的我们不管,就跟DD一起来看看 Spring Boot 2.5.0 的发布吧!看看都带来了哪些振奋人心的新特性和改动! 主要更新 支持 Java 16 支持 Gradl ...
- ART-TEMPLATE的核心语法
模板引擎语法 核心方法 // 基于模板名渲染模板 template(filename, data); // 将模板源代码编译成函数 template.compile(source, options); ...
- 基于Hadoop集群搭建Hive安装与配置(yum插件安装MySQL)---linux系统《小白篇》
用到的安装包有: apache-hive-1.2.1-bin.tar.gz mysql-connector-java-5.1.49.tar.gz 百度网盘链接: 链接:https://pan.baid ...
- java基础——创建对象与内部分布
类与对象的关系 类是一种抽象的数据类型,它是对某一类事物整体描述和定义,但是不能代表某一个具体的事物 动物.植物.手机.电脑... Person类,Pet类,Car类,这些类都是用来描述和定义某一类具 ...