4 ms·
Towards Oberon+ Concurrency
- Rochus 3y agoMaybe you find it easier to read in this format: https://github.com/oberon-lang/oberon-lang.github.io/blob/main/_posts/2023-12-25-towards-concurrency.md https://github.com/oberon-lang/oberon-lang.github.io/blob/ma...
- Rochus 3y agoI initially posted this paper here on HN under the title "Show HN: Towards Oberon+ concurrency; request for comments" in the hope to receive comments specifically on the proposed language extensions.
- yxhuvud 3y agoWell ok. The topic of generics were strangely absent from the channel discussion. That is an alternative solution to the type issue. Adding those is like killing a mosquito with a bazooka, but there are languages (like crystal) that has generics and therefore use them for this. As for the proposal itself, it seems to lack the recognition that channels + ability to spawn fibers/threads has not shown themselves to be sufficient in practice. Most of the time people don't want unbounded and unknown lifetimes on the executors, but instead want to be able to see that directly in the code. In go, that resulted in wait groups, and in other languages (java, swift, kotlin etc) a thing called structured concurrency is talked about, see https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ https://vorpus.org/blog/notes-on-structured-concurrency-or-g... for the article that started that.
- Rochus 3y agoOberon+ already has generics and they should play well with my present proposal: https://github.com/oberon-lang/specification/blob/master/The_Programming_Language_Oberon%2B.adoc#generics https://github.com/oberon-lang/specification/blob/master/The... > Most of the time people don't want unbounded and unknown lifetimes on the executors, but instead want to be able to see that directly in the code. You mean something like join? This can easily be done by adding a channel on which each thread of the interesting group sends when finished. Thanks for the link, I will have a look at it. EDIT: Ok, after looking through the referenced article I can confirm that it is about join and that there is a solution with channels as described. Unfortunately I don't have an example in Oberon yet, but here is one from my C library: https://github.com/rochus-keller/CspChan/blob/6867c1a28e1443633bb99b65652bf58f033f5bb9/test.c#L445 https://github.com/rochus-keller/CspChan/blob/6867c1a28e1443.... What is called a "Nursery" in the article is just a procedure here (testSieve2) which initiates threads in a similar way like Go, passes an eof channel to them an then waits until it receives on this eof channel.
- yxhuvud 3y ago> Oberon+ already has generics and they should play well What I meant was, channel types is something you get for free if they are implemented in terms of generics, without having to resort to custom syntax. Example, in Crystal: `channel = Channel(Int32).new`, which would then only accept and produce Int32. > You mean something like join? I meant an obligatory join, that no fibers or threads can be created without knowing where in the code it will have ended. > This can easily be done The problem is that this is both repetitive and very easy to get wrong. Hence the need for wait groups and/or nurseries.
- Rochus 3y ago> without having to resort to custom syntax But this requires extensive casting features which we don't have in Oberon+. Here is a discussion about this: https://github.com/oberon-lang/oberon-lang.github.io/blob/main/_posts/2023-12-25-towards-concurrency.md#types-of-implementation https://github.com/oberon-lang/oberon-lang.github.io/blob/ma... > I meant an obligatory join This is how it was solved in Occam, Joyce or SuperPascal. It's just another language philosophy, and also less flexible than the detached go routines. Using Go (or Oberon+ in future) requires another way of thinking and architecture. Requiring wait groups or other features from the sync package seem like an indication of a mismatch between the architecture and the language philosophy. I'm actually very interested in what things really don't match the Go (or Oberon+ so far) language philosophy and cannot be solved satisfactorily in Go.
- yxhuvud 3y agoWait groups is a feature that was added to go quite long ago, so the claim that it doesn't match the language philosophy seems more than a little bit strange. Or were you just talking about making them obligatory? I've seen claims though that it is best practice to always use wait groups but I can't judge the quality of those claims as I don't actually program go.
- Rochus 3y agoIf it wasn't part of Newsqueak, then it's very likely not part of the original language philosophy. A lot of things seem to have been added with hindsight to ease migration and support programmers coming from previous thread libraries. > I've seen claims though that it is best practice to always use wait groups Is this from the original authors? Can you provide a reference, please?
- 082349872349872 3y agozK: it's (irregularly, but what in english isn't?) "forty", not "fourty" More importantly, I haven't (yet) read closely enough to tell if you only have blocking constructs in at the moment, but if so you probably want to be able to block on an (unordered) collection of channels. I don't think it matters much if this operation unblocks and performs a channel action or just unblocks when a channel action becomes possible, but it does matter that one should be able to block on a mix of both reads and writes in the same group.
- Rochus 3y agoCurrently there is either SEND or RECEIVE select, not a mixed one. What's the use case you have in mind for a mixed send/receive select?
- gpderetta 3y agoA bidirectional forwarding actor for example?
- Rochus 3y agoIs there a Go example somewhere?
- 082349872349872 3y agoNot Go, but there is example X7 on p117 of http://www.usingcsp.com/cspbook.pdf http://www.usingcsp.com/cspbook.pdf VAR_x = (left?y -> VAR_y | right!x -> VAR_x) as Hoare notes on p116: (not wrt mixed select, but the ultimate logic is the same) > To wait for the first of many possible events is the only way of achieving this: purchase of faster computers is useless. (note that Hoare78 discusses the desirability of output guards in §7.8 but there it isn't clear that they ought to occur mixed with input guards)
- Rochus 3y agoThanks. But I'm I wrong to assume that this could be worked around by two additional processes and channels?
- dang 3y agoThis is fine as a HN submission but not as a Show HN - see https://news.ycombinator.com/showhn.html https://news.ycombinator.com/showhn.html. I've taken "Show HN" out of the title now. Also, every HN submission is implicitly a request for comments, so I took that bit out of the title too. (Submitted title was "Show HN: Towards Oberon+ concurrency; request for comments")
- Rochus 3y agoThe guidelines allow a "chapter of a book". This post is a paper with the description of a concurrency proposal for the Oberon+ programming language, and I would like to receive comments specifically on the proposal (not just any comment or discussion; yet another reason why Show HN fits). Can you please reconsider your decision?
- pvg 3y agoBooks can be Show HNs, chapter of a book is there so authors can show a substantial part of a book they are selling. Most other things, including papers fall under 'other reading material' which falls outside Show HN.
- dang 3y agopvg's answer is correct, but to add a couple things: (1) it's not possible to focus discussion in a particular direction no matter what the title says; commenters will just post whatever they feel like saying. However, (2) for a case like this, it's certainly legit to add a comment of your own to the thread, giving the background to this piece, explaining what's different about it, and saying what feedback you're hoping for. If anything can work, that will.
- deleted 3y ago[deleted]
- dfawcus 3y agoSince I now actually got around to reading the page... You end the section on Go with "Go adopted the concurrency concept from Newsqueak and added new features, such as buffered channels.". However Alef itself added those buffered channels. Which were also available in libthread and libtask, those being what I used before Go came along. One can find copies to the Alef User[1] and Reference[3] guides from the wikipedia page, and Russ Cox's site also has links to PDFs of them [2,4]. The user guide gives the Alef syntax for such buffered channels as: chan(int)[100] kbd; Search for the section titled 'Asynchronous Channels' in the guide. As to buffered channels in general, Hoare's 1985 book mentions (7.3.4 Unbuffered communication) that one could equally use buffered comms as the primitive. One can check the online version at http://www.usingcsp.com http://www.usingcsp.com, so Alef having buffered channels in 1995 doesn't seem like too much of a stretch, especially given the existence of the actor model. You may also wish to reference this [5] brief paper by Russ Cox, it happens to mention a couple more languages (Pan and Promela). Also see [6]. The Alef (and libthread) approaches are interesting that they contain a mixture of threads and coroutines; in the former as a language facility in the latter as a library for C. Now in terms of language syntax forms, having used both libtask in C, and Go, I do appreciate the syntax elements. Having typed (and type enforced) channels in Go makes it easier to reason about the code, likewise the ability (in Go) to split a channel in to a send-only and a receive-only version helps. With typed channels, one can also retrieve a degree of flexibility if the type in question is an interface, then one type switches on receipt of a message. The real gain though is in select syntax, where having to manually manipulate the array of Alt elements in the libtask/libthread implementation was a distraction. Oh - and obviously Go having a GC makes for an easier time, though it is still possible to "leak" channels and/or goroutines if one freely creates/spawns and they're not carefully closed down. Hence my earlier reference to dynamic graphs. I suspect a language with sufficient compile time generics could convert a form of libtask chanalt() call in to something which looks a lot like a Go select statement, and hence avoid the distractions. I was pondering having a go at doing that for a Zig or D library. As to your other question, yes I'd suggest non blocking forms are necessary, I've occasionally had to use them. See the libtask/libthread 'nb' variants. They're actually implemented with a special value in the Alt arrays. I'd imagine a generic version of 'select' taking some form of lambda's could be wrap those without being too ugly. [1] https://doc.cat-v.org/plan_9/2nd_edition/papers/alef/ug [2] https://swtch.com/~rsc/thread/ug.pdf [3] https://doc.cat-v.org/plan_9/2nd_edition/papers/alef/ref [4] https://swtch.com/~rsc/thread/alef.pdf [5] https://swtch.com/~rsc/thread/ [6] https://swtch.com/~rsc/talks/group02-thread.pdf