热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Wrek简介—微型Erlang图引擎

理查德卡洛斯(RichardKallos)Wrek是我为同时执行任务依赖图而编写的Erlang库。目的是运行一组预定义的任务,它们之间有部

理查德·卡洛斯 ( Richard Kallos)

Wrek是我为同时执行任务依赖图而编写的Erlang库。 目的是运行一组预定义的任务,它们之间有部分排序。 在这篇文章中,我解释了为什么写wrek,可以用于什么以及如何使用它。

动机

Wrek是由两种截然不同的力量产生的。 首先,我对图论的业余爱好使我尝试在任何可能的地方查看图,从而为该库奠定了概念基础。 其次,我意识到我在Adgear上从事的项目将从这种库中受益,这使我最终开始编写Wrek。

概念性

该图是计算中的普遍数据结构。 当我在学校学习图算法时,我为它们的广泛应用而感到惊讶。 图在编译器和构建系统中起着至关重要的作用。 各种图形算法构成了我们如何通过Internet相互通信的基础。

我们的日常生活往往充满了清单。 我们有待办事项清单,购物清单,食谱,清单,说明等等。 有一天,我意识到其中一些清单在欺骗。 其中一些列表实际上是隐藏在列表中的图形。 这些列表是有向无环图的 拓扑顺序 。 最明显的两种情况是待办事项清单和配方。 您无法发送尚未写过的信,也可以煮一锅水煮意大利面。

一旦发现了偷偷摸摸的图,我就花了一些时间思考如何从像DAG一样的各种列表中秘密获得收益。 这些清单和DAG之间最清晰的类比是待办事项清单和配方。 这些非常相似的依赖图 。 这些依赖图与列表表示不同,它们显示可以同时执行的顶点(单个任务)。 有时候这很明显(例如:我可以等到一锅水烧开时切碎蔬菜!我可以在第一批饼干在烤箱中时准备第二张饼干烘烤片!),但是我希望将列表重新构造为依赖关系图的行为可能会暴露更多的并发机会。

Boil water -- Add pasta -- Cook pasta --.
\
Purée tomatoes --. \
\ \
Chop vegetables -- Combine in saucepan -- Simmer sauce -- Combine pasta and sauce -- Serve
/
Add spices --'

上图中顶点之间的边表示部分排序。 它们之间没有路径的顶点可以同时执行。 图中顶点之间的关系反映了厨房中的事实。 我们可以在煮酱的时候煮意大利面。 我们先切蔬菜还是番茄泥都没关系。 如果我们要做任何调味料,它们都需要做。

尽管我尽了最大的努力,但我仍然是厨房里的灾难。 作为改变这一不便事实的一种方法,我认为尝试将配方表示为有向图以及附加数据(如预计每个步骤需要多长时间)会很有趣。 这很长时间以来一直存在于我的“有一天的项目”列表中,只有当我开始考虑我在$ JOB从事的项目时,我才想起它。

实际的

我去年在Adgear上完成的项目之一是删除在我们每个已经极限的边缘服务器上进行的昂贵计算,然后将其替换为在单台机器上执行昂贵计算的系统,然后分发结果。 当没有人触摸时,该系统就可以工作,但是它的编程效果等同于细枝和胶带。 cron作业和Shell脚本。 该系统使用起来仍然很痛苦,并且出现了更多在CPU匮乏的计算机上进行昂贵计算的示例。 在这一点上,开始编写一个更强大的系统是有意义的。

这些昂贵的计算很好地分解为要执行的步骤列表。 获取此数据,对其进行转换,对其进行更多转换,将一些数据发送到该组服务器,将该其他数据发送到其他组服务器。 Shell脚本非常擅长编码这些管道,因此在实现时是一个可接受的选择。 过了一会儿,我突然意识到这些步骤清单并不是真正的清单。 它们是依赖图。 我试图通过在shell脚本中添加一些后台作业和waitpid来暴露潜在的并发性,但是我决定切换到Erlang并从OTP提供的所有功能中受益是更有意义的。

让我们来《 Wrek》

(对不起。我无法抗拒。)

Wrek接受像上面的意大利面条食谱这样的依赖图作为输入,并执行每个顶点。 只要能够执行动作,就可以同时执行动作的性质对于依赖关系图可以表示的任何问题都是通用的 。 依赖图的结构以及每个图的顶点所涉及的任务都是特定于用户的意愿的。 遵循与OTP相同的通用/特定划分; 此类问题的通用部分由wrekwrek_vert模块解决。 用户以Erlang映射的形式提供特定部分,该映射描述了图中的每个顶点,以及一组实现wrek_vert的回调模块 行为。

wrek_vert 行为由单个回调run/2 ,其中第一个参数是要发送给回调函数的参数列表,第二个参数是可以提供其他顶点生成的信息的进程的ID。 此回调函数的预期结果是

{ok, Any :: any()} 要么 {error, Reason :: any()} 。 如果回调函数成功,则wrek将使用Any并将其提供给其他wrek_vert进程。 如果回调函数崩溃或返回错误,则将关闭整个图形。

制作Erlang意大利面

按照上面人为设计的示例,让我们开始使用wrek制作意大利面。 当然,我们的程序不会真正制作面食,但是它的输出应该使人蒙昧。

查看上图,每个步骤似乎可以完成以下三件事之一:

  1. 添加成分
  2. 在容器中混合成分
  3. 对容器中的成分进行处理

让我们继续为每个动作编写一些wrek_vert 。 如果您不想跟随文本编辑器,请在此处找到完整的代码。

-module(cook_add).

-behaviour(wrek_vert).
-export([run/2]).

run([Ingredient, Quantity], _Pid) ->
io:format(“adding ~s. amount: ~s.~n”, [Ingredient, Quantity]),
{ok, #{added => [{Ingredient, Quantity}]}}.

这就是cook_add的全部cook_add 。 它打印一条消息,然后生成一个添加了键的映射,该键的值是具有一对的属性列表。

-module(cook_heat).

-behaviour(wrek_vert).
-export([run/2]).

run([Verb, Noun], _Pid) ->
io:format("~ping ~p.~n", [Verb, Noun]),
{ok, #{}}.

cook_heat也很短。 它也非常抽象。 它可以用于打印有关 Verb任何Noun ,而不仅仅是烹饪食材!

我们的最终回调模块要更长一些,因为它比打印消息要执行更多的工作。

-module(cook_combine).

-behaviour(wrek_vert).
-export([run/2]).

run([Ingredients, Vessel], Pid) ->
Fun = fun(Step, Acc) ->
Stuff = wrek_vert:get(Pid, Step, added),
io:format("combining ~p with ~p in ~p.~n", [Stuff, Acc, Vessel]),
Stuff ++ Acc
end,
Stuff = lists:foldl(Fun, [], Ingredients),
io:format("~p now contains: ~p.~n", [Vessel, Stuff]),
{ok, #{added => Stuff}}.

Ingredients应该是顶点名称的列表。 最后,我们使用父进程的Pid作为wrek_vert:get/3的参数。 这使我们可以使用cook_add生成的数据 回调模块。 合并所有内容后,我们将返回一个新的成分集合。

好的! 我们几乎已经完成了描述问题的特定部分的工作! 最后一步是根据这些回调模块和我们要传递给它们的参数来表示我们的依赖图。

-module(wrek_example).

-export([make_pasta/0]).

make_pasta() ->
application:ensure_all_started(wrek),
Graph = #{
tomatoes => #{
module => cook_add,
args => ["pureed tomatoes", "1 can"],
deps => []
},
vegetables => #{
module => cook_add,
args => ["chopped vegetables", "lots"],
deps => []
},
spices => #{
module => cook_add,
args => ["spices", "to taste"],
deps => []
},
saucepan => #{
module => cook_combine,
args => [[tomatoes, vegetables, spices], saucepan],
deps => [tomatoes, vegetables, spices]
},
simmer_sauce => #{
module => cook_heat,
args => [simmer, sauce],
deps => [saucepan]
},
boil_water => #{
module => cook_heat,
args => [boil, water],
deps => []
},
add_pasta => #{
module => cook_add,
args => ["pasta", "1 handful"],
deps => [boil_water]
},
cook_pasta => #{
module => cook_heat,
args => [cook, pasta],
deps => [add_pasta]
},
mix_pasta_with_sauce => #{
module => cook_combine,
args => [[saucepan, add_pasta], saucepan],
deps => [simmer_sauce, cook_pasta]
}
},
wrek:start(Graph).

真是满眼! 我们在这里完成的工作是创建一个Erlang映射,其键代表原始依赖关系图中顶点的名称,其值是指定回调模块,传递给回调模块的参数以及顶点的任何依赖关系的映射可能有。 我对你们中那些注意到我们从不拉紧意大利面的人表示祝贺; 我承认在厨房里是一场灾难。 我保证我学到了教训。

好了,我们完成了编码! 让我们开始一个贝壳,做一些意大利面吧!

阅读有关codesync.global的本博客文章的其余部分。

Code BEAM SF 2018:2018年3月15日至16日

加入CodeBEAM SF的AdGear开发人员Richard Kallos,他将在wrek发表演讲

最初发布于 codesync.global

From: https://hackernoon.com/introducing-wrek-a-miniature-erlang-graph-engine-79196e7ea457



推荐阅读
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了2020年计算机二级MSOffice的选择习题及答案,详细解析了操作系统的五大功能模块,包括处理器管理、作业管理、存储器管理、设备管理和文件管理。同时,还解答了算法的有穷性的含义。 ... [详细]
  • OO第一单元自白:简单多项式导函数的设计与bug分析
    本文介绍了作者在学习OO的第一次作业中所遇到的问题及其解决方案。作者通过建立Multinomial和Monomial两个类来实现多项式和单项式,并通过append方法将单项式组合为多项式,并在此过程中合并同类项。作者还介绍了单项式和多项式的求导方法,并解释了如何利用正则表达式提取各个单项式并进行求导。同时,作者还对自己在输入合法性判断上的不足进行了bug分析,指出了自己在处理指数情况时出现的问题,并总结了被hack的原因。 ... [详细]
  • 关于CMS收集器的知识介绍和优缺点分析
    本文介绍了CMS收集器的概念、运行过程和优缺点,并解释了垃圾回收器的作用和实践。CMS收集器是一种基于标记-清除算法的垃圾回收器,适用于互联网站和B/S系统等对响应速度和停顿时间有较高要求的应用。同时,还提供了其他垃圾回收器的参考资料。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • 数据结构系列1 数组和链表
    数组,链表,l ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文介绍了Shell中for命令的基本格式和用法,通过提供一个值列表来迭代执行一系列命令。同时还介绍了如何读取列表中的值,并给出了for命令与其他命令的结合使用示例。 ... [详细]
author-avatar
用巛户khm8pcnjp9
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有