diff --git a/cpp/dev_BUILD.bazel b/cpp/dev_BUILD.bazel new file mode 100644 index 000000000..8c7470b99 --- /dev/null +++ b/cpp/dev_BUILD.bazel @@ -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, +) diff --git a/cpp/src/ray/example/example.cc b/cpp/src/ray/example/example.cc new file mode 100644 index 000000000..7ada6f1f5 --- /dev/null +++ b/cpp/src/ray/example/example.cc @@ -0,0 +1,134 @@ + +#include +#include +#include + +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 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 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 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 call(args 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 call(args 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 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 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; +} diff --git a/doc/source/index.rst b/doc/source/index.rst index a2edb5432..0ad72114b 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -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 `__ and report issues on GitHub. + Run the following commands to get started: + - Build ray from source with *bazel* as shown `here `__. + - 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 `_. For the latest wheels (nightlies), see the `installation page `__.