一个c++ husky程序的框架如下:
void job() { // work ... } int main(int argc, char ** argv) { Husky::run_job(job, argv[1]); return 0; }
我们在job
函数中实现程序逻辑。首先,我们需要在程序的开头创建一个husky worker.
auto & worker = Husky::Context::get_worker<Husky::BaseWorker>();
相应地,我们需要在程序的末尾移除该worker。
Husky::Context::free_worker<Husky::BaseWorker>();
在我们设置文件中,每一个线程都将创建它们自己的worker。紧接着,我们需要通过该worker创建出husky对象。对象是husky最小单位的数据抽象。例如,我们可以首先定义如下的User
类并接着创建对象。
class User : public Husky::BaseObject { public: typedef int KeyT; // Key type of this class of object const KeyT & id() const { return user_id; } KeyT user_id; // the identity of User object };
如上是最简单的Husky对象。因为它仅仅定义了它的key和对应的key的类型。我们可以从文件中读入数据,创建并初始化这些对象。我们假设输入是文本文件,每一行有一个数字,表示不同用户的id。
auto & user_list = worker.create_list<User>("user-list"); // 创建一个可存储user对象的husky列表 Husky::HDFSLineInputFormat infmt; infmt.set_input("/path/to/file"); worker.load(infmt, [&](boost:string_ref line){ uid = std::stoi(line); User user; user.user_id = uid; worker.add_object(user_list, user); // 往该object list添加对象 });
上述代码创建了一个对象列表,然后按行读入输入文件,并依据该行的数据来创建并初始化对应的对象。每一个worker都会读取整个输入文件中的一部分,使得传输和并行处理的效率最大化。最后,每个worker都创建并保存一些user
对象。
然而,他们并不知道在其他worker上面创建了哪些user
对象。也既是说,在非本地的worker上的对象是不可见的。
可以通过以下方法便可使对象全局可见。
worker.globalize_list(user_list);
有时候,你可能需要从配置文件读入一些参数。例如,我们需要从配置文件取得以上程序中的输入,那么我们应该在配置文件新添加一行并增加一个key:value
对:
input:/data/to/path
请注意这里的key和value是以:
号(需要使用英文输入法)分隔的。这样我们便可以通过Husky::Context::get_params(key)
这个API来取得这一参数:
infmt.set_input(Husky::Context::get_params("input")); // 这里的key是 `input`
需要注意的是,我们从Husky::Context::get_params
取得的永远是 std::string 类型,在某些情况下,您可能需要将其转变成整数或浮点数。
以下例子展现其余用户向user 0发送消息(内容为数字1)。
worker.list_execute(user_list, [&](User & user) { if(user.id() != 0) Husky::send_message(1, 0, user_list); // (Msg, Key, Obj_List) });
当你有许多user的时候,消息传递可能会占用大量网络并限制数据处理速度。为此,Husky提供了Combiner来整合来自同一个worker上的消息。可以如下操作:
worker.list_execute(user_list, [&](User & user) { if(user.id() != 0) Husky::send_message<Husky::SumCombine<int> >(1, 0, user_list); // (Msg, Key, Obj_List) });
在接下来的list_execute, 每一个对象可以获取其他对象发给它的消息。
worker.list_execute(user_list, [&](User & user){ auto & msgs = Husky::get_messages<int>(user); // 消息类型为int int cnt = 0; for (auto m : msgs) cnt += m; if(cnt != 0) Husky::log_msg(std::to_string(user.id())+" recv "+std::to_string(cnt)+" msgs."); });
我们在example/
目录下提供丰富的例子来辅助快速开发一个基于Husky的分布式程序。
例如,pi.cpp
这一文件提供许多基本c++ API的使用方法。wc-mr.cpp
展示了如何使用inputformat
和topk
。pi-agg.cpp
使用了aggregator。
我们将会在后续一些章节中介绍combiner,aggregator和broadcast等API。