-
Seems split and let_value can do same thing, here is the example: #include <stdexec/execution.hpp>
#include <exec/static_thread_pool.hpp>
#include <cstdio>
namespace ex = stdexec;
int main() {
// Declare a pool of 8 worker
threads:exec::static_thread_pool pool(8);
ex::scheduler auto sch = pool.get_scheduler();
auto s0 = ex::schedule(sch);
auto s1 = s0 | ex::then([]() {
std::printf("sender 1\n");
return 1000;
});
auto s1_ = s1 | ex::split();
auto s2 = s1_ | ex::then([](int val){
std::printf("sender 2, val = %d\n", val);
});
auto s3 = s1_ | ex::then([](int val){
std::printf("sender 3, val = %d\n", val);
});
auto s4 = ex::when_all(s2, s3);
ex::sync_wait(s4);
auto let_s4 = s1 | ex::let_value([](const int& val){
auto s2 = ex::just(val) | ex::then([](int val){
std::printf("sender 2, val = %d\n", val);
});
auto s3 = ex::just(val) | ex::then([](int val){
std::printf("sender 3, val = %d\n", val);
});
return ex::when_all(s2, s3);
});
ex::sync_wait(let_s4);
} https://godbolt.org/z/6946G5c5h |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 6 replies
-
Hi, this is a good question! The effect that you achieve for this particular example is very similar, but the algorithms splitThe sender returned by (i) creates a reusable shared state within the sender returned by split Remember, that the input operation is started only once, i.e. you can not even easily use split for repeat-like algorithms, which might require multi-connectable or copyable senders but want to invoke some effect multiple times. let_valueThe sender returned by To summarize (i) The result of the input operation is stored within the operation state of let_value Let value is one of the bread and butter algorithms that you will find to use regularily with S/R. It is decently cheap. There are things you can not (easily) do with one or the other algorithm, they are just different algorithms. |
Beta Was this translation helpful? Give feedback.
-
Right. You'll probably notice the differences if you pass data from the sender to its continuations. let_value() sequences a sender onto another, it's a sender-pipeline-chaining operation, and then some, within one pipeline. split() performs a sender-pipeline fork, giving you two pipelines. |
Beta Was this translation helpful? Give feedback.
-
Ah, yes, indeed.
|
Beta Was this translation helpful? Give feedback.
Hi,
this is a good question! The effect that you achieve for this particular example is very similar, but the algorithms
split
andlet_value
have different purposes.split
The sender returned by
ex::split(std::move(s1))
is always copyable and can be connected multiple times even after it has completed once. But the operation associated withs1
is only started once. If you visualize your senders as a graph, the split algorithm is literally a split that connects one parent node with multiple children. To achieve this, the current implementation(i) creates a reusable shared state within the sender returned by split
(ii) stores the completion result in the shared state upon the completion of…