4 ms·
It's not that I don't see the benefit of the CPU doing something useful when waiting for I/O, my confusion comes from the fact that people like to express this
by gerbilly 5y ago
It's not that I don't see the benefit of the CPU doing something useful when waiting for I/O, my confusion comes from the fact that people like to express this using promises/await.
Why not just arrange it like this?
function non_awaited(cache, db, metrics) {
let result = cache.query(...);
if (!result) {
result = db.query(...);
cache.store(result);
}
metrics.log(...);
return result;
}
Basically doesn't a good threading library just allow you to make all those 'awaits' implicit?
I mean just because await isn't explicitly there, if I run the function above in a thread, my understanding is that the thread does yield to other threads while waiting for I/O.
It's not as if it busy-loops while waiting or something.
- jffry 5y agoI can't speak authoritatively, but I can think of some good reasons you might not want to automatically and implicitly await every invocation of an async function. As designed, calling an async function just returns a Promise, and any Promise can be awaited. This means that I can pass that Promise around, and it also means I can use a Promise-based library (of which there are many) easily from within my async code. An example? What if I want to launch multiple asynchronous tasks in parallel, and then either wait until the first one finishes (a race) or wait until they all finish? Without explicit await, we'd need some syntax to express this. With explicit await, I can store the Promise and then await it when desired, like this: //start both tasks in parallel let fileDataPromise = getFileDataAsync(); let netDataPromise = getNetDataAsync(); //wait until both are finished let fileData = await fileDataPromise; let netData = await netDataPromise; Fortunately there are nice standard library functions for transforming collections of Promises, so we can also just write: let [fileData, netData] = await Promise.all([ getFileDataAsync(), getNetDataAsync() ]);
- gerbilly 5y agoAll right more flexibility, good point. However what languages are you thinking of when talking about this? I've done a lot of Java programming where we commonly use threads and thread pools, although there are non blocking libraries out there too. Is it common these days to mix promises and threads (waiting on a promise in a thread), or is what I just said nonsense?
- jffry 5y agoAh. I was coming at this from the perspective of "why would it be implemented this way in JavaScript specifically", as you'd asked about JS land. More generally, I don't have a good enough overview of programming language trends to speak to how that fits in with other languages' approaches to async. > Is it common these days to mix promises and threads I'm not sure. That probably depends a lot on the evolutionary history of a given language and its library ecosystem. I could see it being done to mix those two things in a world where you are trying to glue together two libraries (or legacy internal modules) built in different ways, and the alternatives either don't exist or are more onerous.
- e12e 5y agoThere was recently an article/discussion on async in ruby: https://news.ycombinator.com/item?id=29049881 https://news.ycombinator.com/item?id=29049881 And I think the example is a good one for how doing parallell io can be simple with async tasks/promises: require "async" require "open-uri" Async do |task| task.async do URI.open("https://httpbin.org/delay/1.6") end task.async do URI.open("https://httpbin.org/delay/1.6") end end (completes in ~time of slowest request, not sum of requests). Sure, one could use threads/processes/green threads etc.