4 ms·
Wait, async is multithreaded by default in Rust? For me the whole point of using async in JavaScript or Python (originally with Twisted's @inlineCallbacks) was
by captainmuon 3y ago
Wait, async is multithreaded by default in Rust? For me the whole point of using async in JavaScript or Python (originally with Twisted's @inlineCallbacks) was to get concurrency without threads.
Imagine writing code for a computer game bot: move left, wait for enemy, attack enemy... You normally can't write it like this because it would block the rest of your program. Async allows you to go from "program sequential" to "bot sequential" for lack of better terms. If you are IO bound there is no need for threads. I often like to use one network thread and one GUI thread to keep things separate, and to prevent the occasional blocking in one to cause latency in the other. You just need to have a method to post calls to the other event loop. Works well in Python, as well with Qt-based apps.
C# on the other hand made the same "mistake" of being very general. I think you can even have a coroutine suspend on one thread and wake on another. It looks like you switch threads in the middle of a function.
I guess that is useful when you want to write performant multithreaded servers. I just want to write easy sequential code without worrying about locks or state machines.
- maeln 3y ago> Wait, async is multithreaded by default in Rust? For me the whole point of using async in JavaScript or Python (originally with Twisted's @inlineCallbacks) was to get concurrency without threads. Async in rust is nothing by default because it doesn't have a runtime. You need to use a runtime/executor for async to work, the most popular being Tokio, which can be configured to be single-threaded or multi-threaded. EDIT: But in a way since Rust make 0 assumption about how async function are going to be executed, it does design around the fact that they might be multi-threaded.
- kibwen 3y ago> Wait, async is multithreaded by default in Rust? No, whether or not async is multithreaded depends on whether or not your executor is multithreaded. Rust doesn't ship an executor by default, you need to bring your own. Tokio, the most popular general-purpose executor, is multithreaded by default, and can be configured to be single-threaded.
- duped 3y agoThe point being made isn't whether or not the futures are evaluated on one thread or many, but that by default, library authors assume that something may be evaluated on multiple threads which imposes some constraints on both the argument and return types from functions. So for example, the tokio executor could run single threaded or on a thread pool. However, tokio::task::spawn takes a future as an argument that may be evaluated on a different thread, so any caller of this API and the designers of the library behind it need to guarantee the argument is thread safe. That constraint is reflected through the type system by constraining the argument type of tokio::task::spawn<T>(fut: Future<Output = T> + impl Send + 'static) which means "fut is a type that implements Future with the output of type T and is Send (safe to send to a different thread) and does not have any lifetimes that outlive the 'static lifetime (contains no references to non-static data)".
- captainmuon 3y agoThat's just what I was trying to say. If your language potentially allows futures to resume on different threads, you pay a complexity cost. I'm not too familiar with Rust, but I think the cost is especially high here because Rust is so concerned with correctness (there is no Send trait in C++ for example). And if you are using async only for nicer control flow, then there is no need for multithreaded executors. Just coroutines that live on a single thread and get orchestrated by an event loop (trampoline/reactor/executor).
- duped 3y agoI think you're still missing it. Rust futures can be evaluated on one thread. They don't need to be Send either. It's that library authors need to add the constraints to their APIs because they may be multithreaded.