twinbasic / lang-design

Language Design for twinBASIC
MIT License
11 stars 1 forks source link

Language support for multi-threading: How? #49

Open mansellan opened 2 years ago

mansellan commented 2 years ago

twinBASIC is designed to support multi-threading. Early reports suggest that low-level Windows threading APIs can be called in twinBASIC, without the active resistance put up by VB6 (is threading even possible in ordinary VBA hosts?)

To make threading accessible though, some kind of language support should be added. I have no idea what that should look like. So I'm opening this issue to start the discussion: what should the language syntax and semantics look like, and how does that affect compiler design?

mansellan commented 2 years ago

Follow up: @WaynePhillipsEA - what's the easiest way you can think of to introduce threads to the twinBASIC ecosystem?

bclothier commented 2 years ago

FWIW, there are some places we can look at for inspiration.

Wikipedia has a good list of languages that does concurrent programming. That can work as a starting point.

One paradigm I can see as more natural to BASIC is a message schema. That would work just like events (but without all the overheads associated with an event). (e.g. see Erlang as an example.

There seems to be at least 3 paradigms to consider:

Eiffel also seems interesting.

fafalone commented 2 years ago

I guess the first step is deciding just how far to take it. Something simple, like a Thread object (maybe WithEvents like Start, Terminate), and a few analogs of things like a critical section/mutex/etc and waitforsingle/multiple. It could expose the thread handle so anyone wanting to do the more advanced things could extend it with API, like VB programmers are used to doing. Or a full blown thing like .NET's System.Threading, which might help bring people back from the dark side.

Gotta see what Wayne has in mind.

Greedquest commented 2 years ago

Go is a language designed specifically around concurrency from the start and from what little I've seen it seems really nice. I fully agree with @bclothier's comments; something leveraging Events rather than Callback methods or message pipes seems most VBx Idomatic idiomatic (PS someone coin a phrase for that mouthful please).

If there are any Go users around please share your insights. IIRC the basic idea for Go is go doAThing(args) registers a new task using doAThing method, the runtime I believe takes care of spawning threads to execute these async tasks according to available machine resources by default, and there are message pipes for sending stuff asynchronously back and forth between routines.

mburns08109 commented 2 years ago

(PS someone coin a phrase for that mouthful please).

(I hereby submit my recently-offered-elsewhere "more 'basic-y'" for your consideration. ...and you don't have to worry about misspelling "idiomatic".)

;-)

mwolfe02 commented 2 years ago

If there are any Go users around please share your insights.

My lead developer, @justinsantoro, writes a lot of utilities in Go, particularly when it comes to processes that would benefit from Go's concurrency support. I've asked him to weigh in here.

mansellan commented 2 years ago

So to my mind, the critical ideas are:

Synchronisation Protection of shared state

Different languages have come up with different solutions to these (often multiple solutions within a single language).

For me, BASIC should try to find a simple paradigm, but ideally one that can interact with the underlying primitives.

bclothier commented 2 years ago

Just FYI updated the list to give some general information about each paradigm at a high level.

On a more general comment... When Microsoft announced the await-async paradigm, it did sound like a very appealing solution. In practice, it turned out to be a very leaky abstraction because it was possible to write it in such way that it made no sense. There was also times where the abstraction ended up getting in the way than helping us reason clearly about how a program should behave.

I think futzing with threads and locks is definitely not BASIC. I need it to enable my laziness. The shared-nothing message approach to my mind seems the most BASIC-y. However, from my little experience with JavaScript's promise paradigm, passing around state as a parameter get verbose very fast. That can be annoying if we used the shared-nothing approach.

rexxitall commented 2 years ago

I agree with bclothier the JS way of multithreading s*** :) Very fast you get messed up and you have no way to even get a list of things whats going on. In my opinion there are at least two scenarios where you want to have multi threading or make use of ALL the cpu cores. First for sure in the GUI. IBM has stated one rle in OS/2. The UI has to respond in any cases within 0.1 seconds. Another great trick of OS/2 was that they have a special thred doing multimedia e.g. sound. So for GUI things and long running tasks you want to have smething like that. Especially also not in the VB.NET C# way. In FORTRAN and JULIA they have also a nice paradigm which is something like PARALEL. If you put this in the code even in for next loops all cores wil work on that whithout further assistance. Great for scaling a drawing, do image processing and all other things where you has a great data amount which is independend from eac other. Database things and scaling moving rotating a CAD drawing comes in mind. It might be crazy but in my opinion the OS/2 API doing Multithreading / processing was very easy to understand, simple and fast. Worked with it around 1989 for a few years (Even in REXX). So it might be worth to keep the boots on and move in the dark caves of the past :)
https://www.os2world.com/wiki/index.php/OS/2_Threads_Cookbook http://os2linux.sourceforge.net/process.html https://www.kacer.biz/os2/czech-warpstock-2002/OS2Multithreading-Presentation.PDF http://www.edm2.com/0509/smp2.html

mansellan commented 2 years ago

Interesting to hear your troubles with async/await @bclothier - I use it extensively at work and never have a problem with it. Can you give some examples?

bclothier commented 2 years ago

@mansellan It's more that to be effective with the paradigm, you have to actually learn what it's not, which is why I alluded to the leaky abstraction. I think this article gives a good primer on where people get it all wrong with the paradigm.

The key point here is that if you have to write such article in the first place, then it was not an intuitive solution that helps people be more productive. The learning path ends up something like this:

  1. Cool! New keywords in C#! I now can do async programming!!!
  2. Why am I getting warning? Oh Ok, I need to do awaits, too.
  3. Gee, I have to make it all async all around? Ok, should be few minutes of copy'n'paste.
  4. This isn't asynchronous! What am I missing? googling
  5. Ooh, I did it all wrong. Ok, let me start over...

This is NOT what I want to see in tB's implementation of multithreading. Hence my comments before. Also see: JavaScript's fun implementations of promises.


Now would be a good time to point out that the industry has grossly abused the terms such as "concurrent", "parallel", "asynchrony", "multithreading" and maybe few more I haven't seen yet. It is easy to say they are all the same thing but it's like saying eagles, pelicans, ostriches and sparrows are all birds. Totally unhelpful.

mansellan commented 2 years ago

Excellent article - succinct and accurate. I'd forgotten just how long it took me to originally assimilate all this when I first started using async/await, this article would have saved me a lot of confusion. The only omission would be the "fun" involved with ConfigureAwait and figuring out what the hell a synchronisation context is.

I suspect we'd also want some way to abstract I/O completion ports, as they're a powerful way to offload work for overlapped IO (perhaps the most useful part of asynchony), without having to get into worker threads at all. I assume that other platforms have a similar primitive available.

justinsantoro commented 2 years ago

If there are any Go users around please share your insights.

My lead developer, @justinsantoro, writes a lot of utilities in Go, particularly when it comes to processes that would benefit from Go's concurrency support. I've asked him to weigh in here.

I've written bits of async/await in C#, promises in javascript, and goroutines in Go and IMO the Go concurrency model is by far the easiest to use once you wrap your head around it. In fact it's so easy that when you are first learning go, it is easy to fall into the trap of using concurrency in places where you do not need it at all. For example, people in the go community often cite seeing new users employing goroutines and channels just to do simple things like loop through an array.

The way it works is you define functions to be run in goroutines and then you plumb communication "pipes" between those goroutines via channels (a basic type in go). A goroutine is essentially a lightweight thread. A single go program can have hundreds of thousands of goroutines running at once.

Here are some links to reference materials for anyone who wants to learn more:

Go language spec:

FAQ:

Here is a code walkthrough:

Relevant talks:

Documentation for the standard lib sync package

rexxitall commented 2 years ago

I just hope that it will be something which is simple. Otherwise i end up again with a own task scheduler cause that is what its for. Its not a process or thread or a goroutine it is a task. Something to do and to be done in parallel and if possible on all cores. And if we are lucky we can get also easy interTASK communications (via different channels. Pipes, TCPIP... ) and TASKresource sharing. :)