matrix_multiply代码解析

news/2025/2/6 9:09:08/

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>;

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任务,可能要经过与多台机器的交互才能得到结果,但对用户来讲是完全透明的。

所以,任务都是具有复合性的,如果你熟练使用框架,可以设计出很多复杂的组件出来。


http://www.ppmy.cn/news/611384.html

相关文章

Java 插入排序

插入排序就是定义一个数 插入之后与前后2个数比较 package me;import java.util.Arrays;public class Me {public static void main(String[] args) {int [] arr {3,2,5,8,6,4,9}; //插入排序int i ,j , k;for (i1;i<arr.length;i){k arr[i]; //待插入的元素for (ji-1;j…

MyBatis if标签的用法

<!--4.1.1 在WHERE条件中使用if需求&#xff1a;实现一个用户管理高级查询功能&#xff0c;根据输入的条件去检索用户信息。这个功能还需要支持以下三种情况&#xff1a;当只有输入用户名时&#xff0c;需要根据用户名进行模糊查询&#xff1b;当只有输入邮箱时&#xff0c;…

Java 选择排序

将数组中的没一个元素都与第一个元素经行比较,如果这个元素小于第一个元素,就将这两个元素交换位置. package me; import java.util.Arrays; public class Me {public static void main(String[] args) {int[] arr {3, 2, 5, 8, 6, 4, 9}; //插入排序for (int i 0; i < ar…

Timer定时器开发

Timer定时器开发 定时器的作用是不占线程的等待一个确定时间&#xff0c;同样通过callback来通知定时器到期。 参考&#xff1a;https://github.com/sogou/workflow 定时器的创建 同样是在WFTaskFactory类里的方法&#xff1a; using timer_callback_t std::function<…

《OpenCV3编程入门》学习笔记6 图像处理(一)线性滤波:方框滤波、均值滤波、高斯滤波

第6章 图像处理 6.1 线性滤波&#xff1a;方框滤波、均值滤波、高斯滤波 6.1.1 图像滤波与滤波器 1.图像滤波&#xff1a;在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制 目的&#xff1a; &#xff08;1&#xff09;抽出对象的特征作为图像识别的特征模式 &#…

如何在Mac上安装 Stable Diffusion 来创作

​ 看着别人玩&#xff0c;是不是特想自己搭建一个&#xff0c;那么现在教程来了。 玩这种需要算力的东西&#xff0c;电脑配置肯定是越高越好了。我的电脑配置如下&#xff1a;​ 接下来就开始安装了。 第一步&#xff1a;安装homebrew 打开terminal终端&#xff08;comma…

Docker镜像优化

Docker镜像优化 原文:Docker镜像优化前言 上篇博文说到使用Visual Studio Tools for Docker帮助我们生成Dockerfile&#xff0c;现在我们讨论下生成的Dockerfile的优劣。 一、以往Dockerfile构建模式 &#xff08;1&#xff09;发布API项目 新建Web API项目&#xff0c;项目名称…

Java 对象的理解

之前写过对象的一遍博客,不过没有写demo 说其是怎样调用方法和访问属性的 这里在补充一下 ,稳固知识, -------------------------------------------------------------------------------- 对象:是类的实例,它是类的变量, 对象在使用前需要声明, 对象声明的格式与基本数据…