4 ms·
Tl;dr the author doesn't understand why having "async operation running in the background" is a useful primitive in a language. Well, for one example, it means
by com2kid 2y ago
Tl;dr the author doesn't understand why having "async operation running in the background" is a useful primitive in a language.
Well, for one example, it means the syntax for kicking off dozens of IO requests and collecting all the results is trivial.
Also I'm tired of people saying "async is infectious!" as if it is something clever.
Having concurrency be part of the type system is a good thing!
- justinclift 2y ago> Tl;dr the author doesn't understand why having "async operation running in the background" is a useful primitive in a language. Isn't that covered in the paragraphs starting with? And if so you could create some other way to run it asynchronously like Go’s go foo().
- ahoka 2y ago"the syntax for kicking off dozens of IO requests and collecting all the results is trivial." Please show me this trivial code, assuming I want to process 12 requests in parallel at most (and always processing 12 at the same time until there's non left to process).
- fabian2k 2y agoIn C# you'd use a Channel for this, which is pretty easy to use. But of course that is built on top of async/await, with those alone it is far from trivial to implement your specific case.
- CookiesOnMyDesk 2y agoSomething like this, depending on how you want your input and output to be supplied. public async IAsyncEnumerable<HttpResponseMessage> SendTwelveRequestsAtATimeAsync(IAsyncEnumerable<HttpRequestMessage> requests) { HttpClient client = new(); List<HttpRequestMessage> requestsBatch = []; await foreach (var req in requests) { if (requestsBatch.Count < 12) { requestsBatch.Add(req); } else { foreach (var res in await Task.WhenAll(requestsBatch.Select(client.SendAsync))) { yield return res; } requestsBatch = []; } } }
- ahoka 2y agoI would not call this trivial. :)
- com2kid 2y agoI'd argue that it is a lot easier than doing it with threads! Promises are a primitive, and async and await keywords in JavaScript is just syntactic sugar around promises (it is sugar around similar constructs in other languages). A promise being just a long running task that will return a result eventually. Being able to grab a promise as an object and pass it around is super useful at times, and it is something I end up using a lot in my JS/TS code. Because it is a language primitive that is also expressed in the type system, more complex systems can safely be built up around it, in the same way that it is easier to build safe(r) complex systems up around threads in languages that have threads as a primitive. (Rust being a great example here of bringing threads into the language, Java being another early example, though their early attempts were not perfect since we've learned a lot since 1995!) Async/await and promises are a great example of a technology that makes doing easy stuff easy, and makes hard stuff possible. tl;dr people need to stop complaining that other multitasking/threading paradigm looks different than their preferred one, each has plusses and minuses and one isn't "better" than others, they just serve different purposes.
- joshka 2y agoThe rust version of this has an inherent complexity that is very similar to your requirement. Processing at most X requests at once is the job of a Semaphore, until there's none left to process is the job of join_set. let mut tasks = JoinSet::new(); let semaphore = Arc::new(Semaphore::new(12)); for i in 0..100 { let semaphore = semaphore.clone(); tasks.spawn(async move { let _permit = semaphore.acquire().await.unwrap(); sleep(Duration::from_secs(1)).await; i * i // simulate some result }); } while let Some(result) = tasks.join_next_with_id().await { let (id, result) = result?; println!("Task {id} result: {result}"); } That allows you to collect the results as they come in and align it to the various ids. If you only care about the final result and nothing why things are processing, let results = tasks.join_all(); The task is written inline there, but could as easily be an async function for i in 0..100 { tasks.spawn(process_request(i, semaphore.clone())); }