[docs] Documentation + example for the C++ language API (#13138)

This commit is contained in:
Ameer Haj Ali 2021-01-02 04:18:41 +02:00 committed by GitHub
parent 9eba1871bb
commit 710615c228
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 223 additions and 1 deletions

74
cpp/dev_BUILD.bazel Normal file
View file

@ -0,0 +1,74 @@
# Bazel development build for C++ API.
# C/C++ documentation: https://docs.bazel.build/versions/master/be/c-cpp.html
load("//bazel:ray.bzl", "COPTS")
cc_library(
name = "ray_api",
srcs = glob([
"src/ray/api.cc",
"src/ray/api/*.cc",
"src/ray/api/*.h",
"src/ray/app/*.cc",
"src/ray/app/*.h",
"src/ray/runtime/*.cc",
"src/ray/runtime/*.h",
"src/ray/runtime/**/*.cc",
"src/ray/runtime/**/*.h",
"src/ray/runtime/task/*.cc",
"src/ray/runtime/task/*.h",
"src/ray/util/*.cc",
"src/ray/util/*.h",
"src/ray/*.cc",
"src/ray/*.h",
"src/ray/worker/default_worker.cc",
]),
hdrs = glob([
"include/ray/*.h",
"include/ray/**/*.h",
"include/ray/**/**/*.h",
]),
copts = COPTS,
linkopts = ["-ldl"],
linkstatic = True,
strip_include_prefix = "include",
visibility = ["//visibility:public"],
deps = [
"//:core_worker_lib",
"//:ray_common",
"//:ray_util",
"@boost//:asio",
"@boost//:thread",
"@com_google_absl//absl/synchronization",
"@msgpack",
],
)
cc_binary(
name = "example",
srcs = glob([
"src/ray/example/*.cc",
]),
copts = COPTS,
linkstatic = True,
deps = [
"ray_api",
],
)
genrule(
name = "ray_cpp_pkg",
srcs = [
"example",
"ray_api",
],
outs = ["ray_cpp_pkg.out"],
cmd = """
WORK_DIR="$$(pwd)" &&
mkdir -p "$$WORK_DIR/python/ray/core/src/ray/cpp/" &&
cp -f $(location example) "$$WORK_DIR/python/ray/core/src/ray/cpp/default_worker" &&
cp -f $(locations ray_api) "$$WORK_DIR/python/ray/core/src/ray/cpp/" &&
echo "$$WORK_DIR" > $@
""",
local = 1,
)

View file

@ -0,0 +1,134 @@
#include <ray/api.h>
#include <ray/api/ray_config.h>
#include <ray/experimental/default_worker.h>
using namespace ::ray::api;
/// general function of user code
int Return1() { return 1; }
int Plus1(int x) { return x + 1; }
int Plus(int x, int y) { return x + y; }
/// a class of user code
class Counter {
public:
int count;
Counter(int init) { count = init; }
static Counter *FactoryCreate() { return new Counter(0); }
static Counter *FactoryCreate(int init) { return new Counter(init); }
static Counter *FactoryCreate(int init1, int init2) {
return new Counter(init1 + init2);
}
/// non static function
int Plus1() {
count += 1;
return count;
}
int Add(int x) {
count += x;
return count;
}
};
int main(int argc, char **argv) {
/// Currently, we compile `default_worker` and `example` in one single binary,
/// to work around a symbol conflicting issue.
/// This is the main function of the binary, and we use the `is_default_worker` arg to
/// tell if this binary is used as `default_worker` or `example`.
const char *default_worker_magic = "is_default_worker";
/// `is_default_worker` is the last arg of `argv`
if (argc > 1 &&
memcmp(argv[argc - 1], default_worker_magic, strlen(default_worker_magic)) == 0) {
default_worker_main(argc, argv);
return 0;
}
/// initialization to cluster mode
ray::api::RayConfig::GetInstance()->run_mode = RunMode::CLUSTER;
/// Dynamic library loading is not supported yet.
ray::api::RayConfig::GetInstance()->lib_name = "";
Ray::Init();
/// put and get object
auto obj = Ray::Put(12345);
auto get_put_result = *(Ray::Get(obj));
std::cout << "get_put_result = " << get_put_result << std::endl;
/// common task without args
auto task_obj = Ray::Task(Return1).Remote();
int task_result1 = *(Ray::Get(task_obj));
std::cout << "task_result1 = " << task_result1 << std::endl;
/// common task with args
task_obj = Ray::Task(Plus1, 5).Remote();
int task_result2 = *(Ray::Get(task_obj));
std::cout << "task_result2 = " << task_result2 << std::endl;
/// actor task without args
ActorHandle<Counter> actor1 = Ray::Actor(Counter::FactoryCreate).Remote();
auto actor_object1 = actor1.Task(&Counter::Plus1).Remote();
int actor_result1 = *(Ray::Get(actor_object1));
std::cout << "actor_result1 = " << actor_result1 << std::endl;
/// actor task with args
ActorHandle<Counter> actor2 = Ray::Actor(Counter::FactoryCreate, 1).Remote();
auto actor_object2 = actor2.Task(&Counter::Add, 5).Remote();
int actor_result2 = *(Ray::Get(actor_object2));
std::cout << "actor_result2 = " << actor_result2 << std::endl;
/// actor task with args which pass by reference
ActorHandle<Counter> actor3 = Ray::Actor(Counter::FactoryCreate, 6, 0).Remote();
auto actor_object3 = actor3.Task(&Counter::Add, actor_object2).Remote();
int actor_result3 = *(Ray::Get(actor_object3));
std::cout << "actor_result3 = " << actor_result3 << std::endl;
/// general function remote callargs passed by value
auto r0 = Ray::Task(Return1).Remote();
auto r2 = Ray::Task(Plus, 3, 22).Remote();
int task_result3 = *(Ray::Get(r2));
std::cout << "task_result3 = " << task_result3 << std::endl;
/// general function remote callargs passed by reference
auto r3 = Ray::Task(Return1).Remote();
auto r4 = Ray::Task(Plus1, r3).Remote();
auto r5 = Ray::Task(Plus, r4, r3).Remote();
auto r6 = Ray::Task(Plus, r4, 10).Remote();
int task_result4 = *(Ray::Get(r6));
int task_result5 = *(Ray::Get(r5));
std::cout << "task_result4 = " << task_result4 << ", task_result5 = " << task_result5
<< std::endl;
/// create actor and actor function remote call with args passed by value
ActorHandle<Counter> actor4 = Ray::Actor(Counter::FactoryCreate, 10).Remote();
auto r10 = actor4.Task(&Counter::Add, 8).Remote();
int actor_result4 = *(Ray::Get(r10));
std::cout << "actor_result4 = " << actor_result4 << std::endl;
/// create actor and task function remote call with args passed by reference
ActorHandle<Counter> actor5 = Ray::Actor(Counter::FactoryCreate, r10, 0).Remote();
auto r11 = actor5.Task(&Counter::Add, r0).Remote();
auto r12 = actor5.Task(&Counter::Add, r11).Remote();
auto r13 = actor5.Task(&Counter::Add, r10).Remote();
auto r14 = actor5.Task(&Counter::Add, r13).Remote();
auto r15 = Ray::Task(Plus, r0, r11).Remote();
auto r16 = Ray::Task(Plus1, r15).Remote();
int result12 = *(Ray::Get(r12));
int result14 = *(Ray::Get(r14));
int result11 = *(Ray::Get(r11));
int result13 = *(Ray::Get(r13));
int result16 = *(Ray::Get(r16));
int result15 = *(Ray::Get(r15));
std::cout << "Final result:" << std::endl;
std::cout << "result11 = " << result11 << ", result12 = " << result12
<< ", result13 = " << result13 << ", result14 = " << result14
<< ", result15 = " << result15 << ", result16 = " << result16 << std::endl;
Ray::Shutdown();
return 0;
}

View file

@ -9,7 +9,7 @@ Getting Started with Ray
Check out :ref:`gentle-intro` to learn more about Ray and its ecosystem of libraries that enable things like distributed hyperparameter tuning,
reinforcement learning, and distributed training.
Ray provides Python and Java API. And Ray uses Tasks (functions) and Actors (Classes) to allow you to parallelize your code.
Ray provides Python, Java, and *EXPERIMENTAL* C++ API. And Ray uses Tasks (functions) and Actors (Classes) to allow you to parallelize your code.
.. tabs::
.. group-tab:: Python
@ -112,6 +112,20 @@ Ray provides Python and Java API. And Ray uses Tasks (functions) and Actors (Cla
}
}
.. group-tab:: C++ (EXPERIMENTAL)
The C++ Ray API is currently experimental with limited support. You can track its development `here <https://github.com/ray-project/ray/milestone/17>`__ and report issues on GitHub.
Run the following commands to get started:
- Build ray from source with *bazel* as shown `here <https://docs.ray.io/en/master/development.html#building-ray-full>`__.
- Run `cd ray/cpp`.
- Run `cp dev_BUILD.bazel BUILD.bazel`.
- Modify `src/ray/example.cc`.
- Run `ray stop`.
- Run `bazel build //cpp:example`.
- Run `bazel run //cpp:example`.
.. literalinclude:: ../../cpp/src/ray/example/example.cc
:language: cpp
You can also get started by visiting our `Tutorials <https://github.com/ray-project/tutorial>`_. For the latest wheels (nightlies), see the `installation page <installation.html>`__.