You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
and then any io object can handle it in a same way.
std::cout << my_class;
std::ofstream << my_class;
tcp_stream << my_class;
windows_named_pipe_stream << my_class; // just assume it.
What if we create something like std::async_ostream?
std::async_ostream satisfies stdexec::sender, while stdexec::sync_wait it has no effect.
std::async_ostream << "Hello" also returns a stdexec::sender who will then send the message asynchronously.
The algorithms like std::endl, std::flush is kept same.
When we overload the sync std::ostream& operator<< funciton, it will also register the async one.
For example,
auto task = stdexec::just(tcp_stream("nvidia.com"))
| stdexec::let_value([] (tcp_stream& stream)
{
// Async send some message. Returns a sender.
return stream << "Request Line" // This line is lazily sended (until next time std::flush, std::endl, std::iostream::sync(), or cache is full).
<< "Request Data" << std::flush; // This line is explicit sended.
});
| stdexec::let_value([] (tcp_stream& stream)
{
// Asyn receive some message. Returns a sender.
return stream >> response;
});
| stdexec::then([] (auto&&...)
{
std::cout << response;
});
stdexec::sync_wait(task); // Start the whole workflow asynchronously.
For point 4, we can even make (sync) std::iostream also as sender (maybe through template-specialization ?) which shares similar interface as async-one, although sync_wait it has no effect. Or we might create some algorithm like std::ostream << become_async which turns sync-stream& into async_stream& vice versa.
Pros
Easy. For most of us, the first C++ lesson might be like this:
#include <iostream>
using namespace std;
int main () {
cout << "Hello, world" << endl;
}
and almost everyone can learn asynchronous-io, just by replacing cout to some kind of async_stream then sync_wait the stream in a proper place. Everything will work as same.
and everything will be automatically written into stream. All details are hidden to user (while providing other interface like std::flush or std::basic_streambuf::setbuf() to those user who desires a deeper control on it).
We can also integrate with algorithms in std::ranges like below:
sender = std::views::istream<char>(async_istream) // Ok this is a `sender`.
| std::views::transform(to_upper) // Ok this is also a `sender`.
(if the future std-network-library is in similar interface as boost::asio who is also a high-quality and widely-verified I/O library) The above code on student might become like this
Notice that the current (existing) std::iostream wraps the operations (their sync version) above in an implemention-class called std::streambuf, which, in most cases, (the current existing) std::iostream thinks the user does not need to touch it.
Cons
Where do we store the params who is waiting to be sent? Consider this case:
async_ostream << nomoveable("Hello, world") // The sync-std::iostream uses lvalue-reference. But what should we use here?
<< huge_eigen_matrix; // Oh no, imagine the huge matrix will be destructed right after this line.
Although sync std::iostream often stores the stringalized message in its cache (until explicit-std::flush or cache-is-full), is it acceptable to store stringalized message in async-stream cache ? (worse: this cache might be not fixed-size)
(I'm AnonymousPC who create #1501Adapt boost::asio to stdexec PR. For unknown reason my github account has been suspended without any reason or ways to contact, along with #1501 PR disappearred (???). So I currently use this temp account to join discussion).
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
This primary discussion has only mentioned the idea and possibility. Welcome to discuss about anything, the idea, the code, or the implemention !
Idea
As is known to all,
std::iostream
is a successful and widely-used abstraction of synchoronous-IO. Once we declared anoperator<<
like thisand then any io object can handle it in a same way.
What if we create something like
std::async_ostream
?std::async_ostream
satisfiesstdexec::sender
, whilestdexec::sync_wait
it has no effect.std::async_ostream << "Hello"
also returns astdexec::sender
who will then send the message asynchronously.std::endl
,std::flush
is kept same.std::ostream& operator<<
funciton, it will also register the async one.For example,
For point 4, we can even make (sync)
std::iostream
also assender
(maybe through template-specialization ?) which shares similar interface as async-one, althoughsync_wait
it has no effect. Or we might create some algorithm likestd::ostream << become_async
which turnssync-stream&
intoasync_stream&
vice versa.Pros
Easy. For most of us, the first C++ lesson might be like this:
and almost everyone can learn asynchronous-io, just by replacing
cout
to some kind ofasync_stream
thensync_wait
the stream in a proper place. Everything will work as same.Clear. We only needs to write
and everything will be automatically written into stream. All details are hidden to user (while providing other interface like
std::flush
orstd::basic_streambuf::setbuf()
to those user who desires a deeper control on it).We can also integrate with algorithms in
std::ranges
like below:(if the future std-network-library is in similar interface as boost::asio who is also a high-quality and widely-verified I/O library) The above code on
student
might become like thisNotice that the current (existing)
std::iostream
wraps the operations (their sync version) above in an implemention-class calledstd::streambuf
, which, in most cases, (the current existing)std::iostream
thinks the user does not need to touch it.Cons
Where do we store the params who is waiting to be sent? Consider this case:
Although sync
std::iostream
often stores the stringalized message in its cache (until explicit-std::flush or cache-is-full), is it acceptable to store stringalized message in async-stream cache ? (worse: this cache might be not fixed-size)(I'm
AnonymousPC
who create #1501Adapt boost::asio to stdexec
PR. For unknown reason my github account has been suspended without any reason or ways to contact, along with #1501 PR disappearred (???). So I currently use this temp account to join discussion).Beta Was this translation helpful? Give feedback.
All reactions