Live data from Hacker News

Asynchrony is not concurrency

kristoff.it

201–210 of 228 posts

Re: Asynchrony is not concurrency

#201
post #195
post #157

Defining async is hard. And I'm writing this as one of the many people who designed async in JavaScript. I don't quite agree with the definition in this post: just because it's async doesn't mean that it's correct. You can get all sorts of user-land race conditions with async code, whether it uses `async`/`await` (in languages that need/support it) or not. My latest formulation (and I think that it still needs work)…

i am not even sure we should define async it may be hard (it is) because it cannot be matched to one thing the question is: is it useful to define async? or event loop? there must be tons of concepts i have no idea in the realm of physical chips that make true parallelism possible i am totally fine with "user finger" and "quickies", job queues and blocking or non-blocking APIs the finger symbolizes touch events and e…

Not entirely sure what you mean.

If you're writing that you don't need to understand how your browser works, "just" to make things fast enough... well, sure, go ahead.

But anybody who wants to graduate to a higher-level of comprehension, will need to understand a bit better under the hood.

Re: Asynchrony is not concurrency

#202
post #87

"Asynchrony" is a very bad word for this and we already have a very well-defined mathematical one: commutativity. Some operations are commutative (order does not matter: addition, multiplication, etc.), while others are non-commutative (order does matter: subtraction, division, etc.). try io.asyncConcurrent(Server.accept, .{server, io}); io.async(Cient.connect, .{client, io}); Usually, ordering of operations in code…

> Usually, ordering of operations in code is indicated by the line number (first line happens before the second line, and so on), but I understand that this might fly out the window in async code

This isn’t always true at the language level, and almost certainly not at the CPU pipeline and microcode level.

Logic languages like Prolog will execute statements out of order, by design. Other languages like Mercury use the IO monad to signify serial operations

Re: Asynchrony is not concurrency

#203

I think I'm missing something here, but the most interesting piece here is how would stackless coroutines work in Zig? Since any function can be turned into a coroutine, is the red/blue problem being moved into the compiler? If I call: io.async(saveFileA, .{io}); Is that a function call? Or is that some "struct" that gets allocated on the stack and passed into an event loop? Furthermore, I guess if you are dealing wi…

I hope this is not a bad answer as I tried to understand what stackless coroutines even are for the past week. 1. Zig plans to annotate the maximum possible stack size of a function call https://github.com/ziglang/zig/issues/23367 . As people say, this would give the compiler enough information to implemented stackless coroutines. I do not understand well enough why that’s the case. 2. Allegedly, this is only possibl…

> As people say, this would give the compiler enough information to implemented stackless coroutines.

Stackless coroutines require creating a structure big enough to hold all the locals for the would-be function, but Zig already has that information, along with Rust, and, by definition, every other language that already supports stackless coroutines.

The root of that linked issue is that Zig has some desire to statically compute the total stack usage of an entire program, but the difficulty there is not in computing the stack size for any given function (which is generally trivial in most languages; supporting growable stack via something like C's `alloca` is the exception, not the rule). The difficulty is that recursive functions can push an unbounded number of function calls to the stack. So what Zig wants to do is forbid recursion, even mutual recursion, unless you do some kind of opt-in.

And this is where "Allegedly, this is only possible because zig uses a single compilation unit" comes in, because detecting mutual recursion is tricky, especially when virtual dispatch gets involved.

But no, you don't need Zig-style whole-program compilation to make that happen. All you need is 1) to be able to detect mutual recursion within a single compilation unit (again, stymied by virtual dispatch), and then 2) to prevent cyclical dependencies between compilation units. Go and Rust both do the latter, so they could get away with the same analysis, assuming you can find a good solution for the former.

Re: Asynchrony is not concurrency

#204
post #176

Earlier quoted context omitted.

cries in Python asyncio

sympathizes If you look on the bright side, it looks like free-threading is approaching, and OCaml has demonstrated how, by removing the GIL and adding exactly one primitive, you can turn a powerful enough language into a concurrency/parallelism powerhouse with minimal user-visible changes!

[deleted]

Re: Asynchrony is not concurrency

#205

IMO the author is mixed up on his definitions for concurrency. https://lamport.azurewebsites.net/pubs/time-clocks.pdf

Keep in mind that you can’t really express half the concepts in lamport’s papers in most languages. You don’t really talk about total and partial clock ordering when starting a thread. You only really do it in TLA+ when designing a protocol. That being said, I agree we don’t need a new term to express “Zig has a function in the async API that throws a compilation error when you run in a non-concurrent execution. Zig…

[deleted]

Re: Asynchrony is not concurrency

#206
post #97
post #87

"Asynchrony" is a very bad word for this and we already have a very well-defined mathematical one: commutativity. Some operations are commutative (order does not matter: addition, multiplication, etc.), while others are non-commutative (order does matter: subtraction, division, etc.). try io.asyncConcurrent(Server.accept, .{server, io}); io.async(Cient.connect, .{client, io}); Usually, ordering of operations in code…

Strictly speaking commutativity is defined over (binary) operations - so if one were to say that two async statements (e.g. connect/accept) are commutative, I would have to ask, "under what operation?" Currently my best answer for this is the bind (>>=) operator (including, incidentally, one of its instances, `.then(...)`), but this is just fuzzy intuition if anything at all.

Under function composition `;`, where both the LHS and RHS are viewed as functions operating on the whole environment state.

Re: Asynchrony is not concurrency

#207
As a network programmer who has written a metric asston of concurrent parallel asynchronous whatever-the-hell code [0], this article is confusing. It seems like doing somersaults over a leaky abstraction. The tool for the job is wrong and its implementation is wrong if you can shit the bed this easily.

[0] debugging is fun precisely because it’s amusing to watch people be frightened of having to debug multi threaded hydras.

Re: Asynchrony is not concurrency

#208
post #87

"Asynchrony" is a very bad word for this and we already have a very well-defined mathematical one: commutativity. Some operations are commutative (order does not matter: addition, multiplication, etc.), while others are non-commutative (order does matter: subtraction, division, etc.). try io.asyncConcurrent(Server.accept, .{server, io}); io.async(Cient.connect, .{client, io}); Usually, ordering of operations in code…

Commutativity is a much weaker claim because one is totally before or after the other. e.g. AB may commute with C so ABC=CAB but it is not necessarily the case that this equals ACB. With asynchrony you are guaranteed ABC=ACB=CAB. (There may be an exisiting mathematical term for this but I don't know it)

I agree. T and U async with respect to each other means at least that T and U can be broken down into tasks t1, t2, t3, ... tn and u1, u2, ..., un, such that they can be interleaved in any order, but typically we still require that the t tasks are executed in sequential order. The divisions between the tasks are where they give up control, e.g. as they wait for data to be loaded into memory, or on a network call.

This is still a special case of what we mean by async wrt each other, because depending on the interleaving at each step and e.g. the data loaded into memory, the number of tasks may change, but the idea is that they still eventually terminate in a correct state.

Re: Asynchrony is not concurrency

#209
post #97

Earlier quoted context omitted.

Strictly speaking commutativity is defined over (binary) operations - so if one were to say that two async statements (e.g. connect/accept) are commutative, I would have to ask, "under what operation?" Currently my best answer for this is the bind (>>=) operator (including, incidentally, one of its instances, `.then(...)`), but this is just fuzzy intuition if anything at all.

Under function composition `;`, where both the LHS and RHS are viewed as functions operating on the whole environment state.

Right; though it's a special kind of function composition (Kleisli composition) and often presented in a different form (bind, >>=).

Re: Asynchrony is not concurrency

#210
post #87

"Asynchrony" is a very bad word for this and we already have a very well-defined mathematical one: commutativity. Some operations are commutative (order does not matter: addition, multiplication, etc.), while others are non-commutative (order does matter: subtraction, division, etc.). try io.asyncConcurrent(Server.accept, .{server, io}); io.async(Cient.connect, .{client, io}); Usually, ordering of operations in code…

> Usually, ordering of operations in code is indicated by the line number (first line happens before the second line, and so on), but I understand that this might fly out the window in async code This isn’t always true at the language level, and almost certainly not at the CPU pipeline and microcode level. Logic languages like Prolog will execute statements out of order, by design. Other languages like Mercury use th…

I'm not sure what you mean by "statements" in Prolog as it's not a term the language defines. If you're referring to clauses, it's not true that execution is unordered: the Prolog interpreter attempts to unify a goal with clauses from the knowledge base in the order they appear. This ordering is semantically significant for control flow.

If instead you're referring to goals within the body of a clause, this is also incorrect. Goals are evaluated strictly left-to-right, and each must succeed before the next is attempted. This evaluation order is likewise required and observable, especially in the presence of side effects.

Post reply on HN