3 ms·
Can someone explain to me the attraction of async programming? I don't really do JS, where a lot of this seems to be happening, but the code I have seen with t
by gerbilly 5y ago
Can someone explain to me the attraction of async programming?
I don't really do JS, where a lot of this seems to be happening, but the code I have seen with the huge ladders of callbacks doesn't seem so great to work with to me.
Also, although using promises seems better, it seems like it could quickly become spaghetti.
- kall 5y agoWorking with Promises and async/await doesn‘t really turn into spaghetti in my experience. Biggest downsides are the function coloring and the lack of cancellation primitives. They usually fit the problems I‘m solving pretty well and play well enough with functional programming styles. Having never worked with threads heavily, they always seemed like WAY more hassle to me. I assume that‘s the alternative? I think go has something else?
- jffry 5y agoIf you mean non-blocking in general, the benefit is that your system can do something else useful while it's waiting for some operation to complete (usually things accessing files or a database or a network service) If you specifically mean async/await syntax, let me illustrate with a contrived example. It can let you express a sequence of asynchronous operations in a more natural way: function promised(cache, db, metrics) { return cache.query(...).then(cachedResult => { if (cachedResult) { return cachedResult; } else { return db.query(...).then(dbResult => { return cache.store(dbResult).then(_ => dbResult); }); } }).then(finalResult => { metrics.log(...); return finalResult; }); } async function awaited(cache, db, metrics) { let result = await cache.query(...); if (!result) { result = await db.query(...); await cache.store(result); } metrics.log(...); return result; }
- gerbilly 5y agoIt'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.
- loeg 5y agoIn your async example, each await could just be a blocking operation - it’s all serialized. The blocking sleeps, yielding the processor for other work. Like, maybe context switching is a little more expensive, maybe a normal thread’s stack consumes more memory than an async context. The utility of native async is when you spawn multiple async tasks before awaiting. This is cheaper than spinning up some threads or handing off to a threadpool.
- Noughmad 5y agoEssentially, the attraction is being able to wait for multiple things at the same time within a single thread. It's useful for things like webservers that want to handle thousands of connections simultaneously, but most of these connections aren't actually doing anything useful, they are waiting on the filesystem or the database connection or some other network service. And you can't really spawn thousands of OS threads because those have non-trivial overhead. Now, you may think this can be done in C with the `select()` API and many switch statements. And you would be correct. All these "async" languages and framework are wrappers around this that let you write your code in a procedural manner, and take care of the select and switch for you.
- artursapek 5y agoLeveraging multiple threads can allow your program to get more done, and if it's a graphical application you can also reduce blocking in the UI thread to an absolute minimum.