Multi Threadedness ?

Something you want to see in a LiveCode product? Want a new forum set up for a specific topic? Talk about it here.

Moderators: Klaus, FourthWorld, heatherlaine, robinmiller, kevinmiller

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 6236
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Multi Threadedness ?

Post by FourthWorld » Fri Aug 10, 2018 9:34 pm

LCMark wrote:
Fri Aug 10, 2018 5:04 pm
(I'm pretty sure that a good deal of 4D's multi-processing capabilities could actually be implemented as a well designed script library - based upon open process and elimination of the use of 'wait with messages' in calling code - i.e. without non-recursive wait and workers. So only a few smallish engine changes would be required.)
I realize you have your hands full right now, but when you can spare a moment to show a typical example and how it could become more async-friendly I'd appreciate the opportunity to learn from that.
Richard Gaskin
Community volunteer LiveCode Community Liaison

LiveCode development, training, and consulting services: Fourth World Systems: http://FourthWorld.com
LiveCode User Group on Facebook : http://FaceBook.com/groups/LiveCodeUsers/

bogs
Posts: 2384
Joined: Sat Feb 25, 2017 10:45 pm

Re: Multi Threadedness ?

Post by bogs » Fri Aug 10, 2018 9:41 pm

FourthWorld wrote:
Fri Aug 10, 2018 9:34 pm
LCMark wrote:
Fri Aug 10, 2018 5:04 pm
(I'm pretty sure that a good deal of 4D's multi-processing capabilities could actually be implemented as a well designed script library - based upon open process and elimination of the use of 'wait with messages' in calling code - i.e. without non-recursive wait and workers. So only a few smallish engine changes would be required.)
I realize you have your hands full right now, but when you can spare a moment to show a typical example and how it could become more async-friendly I'd appreciate the opportunity to learn from that.
I'd second that motion :twisted:
Image

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 996
Joined: Thu Apr 11, 2013 11:27 am

Re: Multi Threadedness ?

Post by LCMark » Sat Aug 11, 2018 2:04 am

@Mikey: Heh - yes. Armed with the knowledge I extracted from the 4D docs yesterday, and with your very eloquent description of your system, I have a much greater understanding of both. Indeed, I *think* it has helped me finally solve a problem (or at least put me on a path to solve a problem) which has been causing me irritation for years (to do with event handling but that's definitely for another day!).

Now I notice you did delete some stuff from your original post (if you hadn't had said that you had I probably wouldn't remembered!) - that actually gave me cause to check the version of the page I had on my phone which was the original. I kinda get why you deleted it - but failed experiments (or thoughts) still give useful information (in this case, potentially use-cases which could cause a potential solution to just be plain wrong). The other reason I dug it up was your comment about 'waitDepth' which deserves a significant enough digression as to require me split my response into at least 2 parts...

Part (1) - on waitDepth issues:

The issue you see with waitDepth is down to what I keep referring to as 'the recursive wait problem'. Actually I should be more accurate here - the recursive wait problemS - there are actually two. Although perhaps I should just start referring to them as 'the wait problemS' as only one is only really due to recursion, the other isn't really to do with recursion, but can't be solved because of something which is recursive which ideally would not be. Anyway, that is largely not entirely relevant to any description of either...

The first of these problems can perhaps simply be expressed as 'in an expected strictly ordered pair of actions 1 and 2, action 2 fires when action 1 has not finished':

Code: Select all

on mouseDown
  ... process stuff ...
  get url <some very large file> <-- this does an implicit wait with messages
  ... process result ...
end mouseDown

on mouseUp
  ... do stuff which really shouldn't happen until after mouseDown has finished ...
  ... oh dear, typically it will be called before mouseDown has finished ...
end mouseUp
I use mouseUp/mouseDown here because it is easy to visualize, but it basically occurs when you have two actions which are fired as a result of an event, the second is expected to occur strictly after the first. The problem occurs when the first action calls something which uses 'wait with messages' either implicitly or explicitly.

The problem this causes is that the second action can (and will!) fire before the state it expects on is actually correct - i.e. because the first action hasn't actually completed and thus set the state to the expected values.

Why is this related to waitDepth? Because if in the second action you also call something which either implicitly or explicit calls 'wait with messages', you end up with waitDepth > 1 - which you would not (necessarily by looking at the code) expect it to be.

The second problem is probably actually the main cause of waitDepth issues - but is usually made worse / triggered by some form of the first problem. (In actually fact these two cases can get so intertwined, its primarily why I label this as 'the recursive wait problem' even though that's not strictly accurate). Essentially as soon as an action causes a wait with messages, any action which is a result of an event which occurs during that wait with messages must resolve *before* the action which caused the wait with messages in the first place can.

Whilst this might seem like an 'oh well that's obvious' kind of thing - it arises in unexpected scenarios, mainly because of implicit wait with messages; or because codepaths can get pretty deep and it can easily occur without realizing as code evolves / gets refactored and components get improved/rewritten/made more powerful (although 'get url' is usually the main culprit in more simple projects!).

By far the best visualizable example of where this form of the problem occurs is:

Code: Select all

-- In button of one stack
on mouseUp
  answer "Hello World!" as sheet
end mouseUp

-- In button of another stack
on mouseUp
  answer "Goodbye World!" as sheet
end mouseUp
Due to the recursive (C-stack wise) nature of the engine's interpreter, and the fact that events are dispatched *at any wait with message point* if you click on the button in the first stack - you'll get a dialog. You will then be able to click in the button of the second stack and also get a dialog. Now, here, you must close the *second* dialog before you can close the first dialog - even though the *expectation* is that they should be logically independent!

Note - that *exactly* the same effect can occur with complex sequences of pure code actions which do non-simple things with wait with messages - it is essentially a deadlock of sorts (well only of sorts in the dialog version, since you can click to remove the dialogs - but it can be true deadlock in code if there is no way to explicitly break it).

Why is this related to waitDepth? Well if you have opened both dialogs - the waitDepth will be at least 3 - until the second dialog is dismissed, at which point it will go down to 2, then returning to 1 again (which is the minimum it can be when running script as all scripts run as a result of an event) when the first dialog is dismissed.

So anyway, in more complicated projects which push LC's model to the limit you can essentially end up with a recursive stack of handlers which is the equivalent of nested spaghetti (uncooked tagliatelle perhaps?) internally - not actually knotted (because such pasta isn't ever knotted because of how it is made, it just *looks* that way) and usually results in the IDE going exceptionally wonky too. In serious case of this, if you do manage to coax the message box into appearing and functioning and finally manage to get it to do 'put the waitDepth', you find waitDepth > 1 and probably make lots of sounds which would not be family friendly. In this case I tend to find rapid repeated depressing of Cmd+. (on Mac / Ctrl on Win) can often unwind the mess - although not in all cases, and that's when 'Force Quit' can be the only option.

So before you ask 'why if you know about this have you not fixed it?!?!'. There are three reasons for this.

The first is that this kind of thing only really arises when you start to push the bounds of what LiveCode's version of the xTalk event handling / script mode to beyond what it was originally really designed for - in most developers use of it, when these things arise it is because of small coding errors you did not intend and when you fix those, it goes away (this is usually the case when waitDepth appears wonky at very sparse random points). Indeed, most people tend to find 'something wonky happened when I did that' so they don't do it again.

The second is that if you are a 'power-user' that wants to push the envelope, then you should be able to follow appropriate sanitised coding techniques to be able to do stuff like this without causing the problem to occur. Of course, in order to do this, you either have been told what these techniques are; or have realized there is a limitation in the wait model of LC and figured out yourself how to write code which does not encounter it.

The third is that fixing it correctly/completely/properly is a very very hard thing to do! All solutions require quite time consuming, tedious and extensive transformations of the engine's C++ code, or introduction of quite a large amount of code 'machinery' in lots of places in the code which would only serve to make the code of the engine appear to be more convoluted. Essentially all come down to either eliminating the recursive event handling nature of the engine; or working around it by clever use of real threads (but ones constrained to be co-operative, and not pre-emptive)... And even then it only partially solves the problem! (Oh and some solutions have quite large implications for externals / extension writers who need to use native code!).

Anyway, this has already got too long - so I shall actually leave it here for now and come back to the *actual* point of this thread in a subsequence post (which will likely be tomorrow - I have 9hrs to kill at JFK airport tomorrow afternoon!).

Mikey
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 643
Joined: Fri Jun 27, 2008 9:00 pm

Re: Multi Threadedness ?

Post by Mikey » Sat Aug 11, 2018 2:40 am

Mark,
For my discussion, waitDepth is only a problem if we are dealing with a single thread, because we are trying to manually manage the events that in a multi-threaded setup would be handled directly by the scheduler.
The two paragraphs on the script library I removed because I missed the part where you mentioned adding processes to the engine and doing the rest with a script library. What I thought you were saying was that we could approximate threads with a script library (which is what we're attempting to do now), but relying on waitDepth to ensure that the scheduler waited until tasks that had been started achieved before firing another.
If waitDepth is subject to corruption, then for the time-being I think we may have to build a manual task tree and poor-mans-semaphores to keep things straight. That may at least remove one failure mode and get us to two days between force quits.

Mikey
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 643
Joined: Fri Jun 27, 2008 9:00 pm

Re: Multi Threadedness ?

Post by Mikey » Sat Aug 11, 2018 2:40 am

Mark,
For my discussion, waitDepth is only a problem if we are dealing with a single thread, because we are trying to manually manage the events that in a multi-threaded setup would be handled directly by the scheduler.
The two paragraphs on the script library I removed because I missed the part where you mentioned adding processes to the engine and doing the rest with a script library. What I thought you were saying was that we could approximate threads with a script library (which is what we're attempting to do now), but relying on waitDepth to ensure that the scheduler waited until tasks that had been started achieved before firing another.
If waitDepth is subject to corruption, then for the time-being I think we may have to build a manual task tree and poor-mans-semaphores to keep things straight. That may at least remove one failure mode and get us to two days between force quits.

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 6236
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Multi Threadedness ?

Post by FourthWorld » Sat Aug 11, 2018 5:04 am

LCMark wrote:
Sat Aug 11, 2018 2:04 am
By far the best visualizable example of where this form of the problem occurs is:

Code: Select all

-- In button of one stack
on mouseUp
  answer "Hello World!" as sheet
end mouseUp

-- In button of another stack
on mouseUp
  answer "Goodbye World!" as sheet
end mouseUp
Due to the recursive (C-stack wise) nature of the engine's interpreter, and the fact that events are dispatched *at any wait with message point* if you click on the button in the first stack - you'll get a dialog. You will then be able to click in the button of the second stack and also get a dialog.
On Ubuntu, with or without the "as sheet" clause the first dialog automatically goes away when the second dialog is invoked (LC v9.0.1; Ubuntu 14.04). Bug?
Richard Gaskin
Community volunteer LiveCode Community Liaison

LiveCode development, training, and consulting services: Fourth World Systems: http://FourthWorld.com
LiveCode User Group on Facebook : http://FaceBook.com/groups/LiveCodeUsers/

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 996
Joined: Thu Apr 11, 2013 11:27 am

Re: Multi Threadedness ?

Post by LCMark » Sat Aug 11, 2018 5:17 am

@FourthWorld: Probably - although I'd be inclined to say that the window manager concept on Linux is one giant bug ;)

Although, I'm pretty sure window modal dialogs on Linux did work at some point and, indeed, application modal dialogs should stack...

By the way, which part in regards to async-friendliness did you want me to expand on?

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 996
Joined: Thu Apr 11, 2013 11:27 am

Re: Multi Threadedness ?

Post by LCMark » Sat Aug 11, 2018 5:57 pm

@Mikey
The two paragraphs on the script library I removed because I missed the part where you mentioned adding processes to the engine and doing the rest with a script library. What I thought you were saying was that we could approximate threads with a script library (which is what we're attempting to do now), but relying on waitDepth to ensure that the scheduler waited until tasks that had been started achieved before firing another.
The engine already has process support (open process), it is just a bit of a pain to use in an async manner as you need to poll, rather than use 'with message' like sockets (admittedly that is just a thing which really irks me - the actual end effect is the same, the code is just less 'pretty' then it could be).

Actually making a stack which bootstraps itself into separate processes is perfectly feasible (but, again, a bit fiddly - node.js has a really nice abstraction there which I've had on my list to blatantly steal for quite a while). Indeed, the LiveCode installer (all code available in the github repo) does that.

As the core part of the installer needs to run with privilege, it is a split process model with UI using a faceless stack underneath. Indeed, it is the same stack, it just launches the faceless side by open processing (with elevation, in this case) itself, and then using the standard read process poll-loop to talk to it. (I'll not mention how purely evil the code to do process elevation at the engine-level is though - if anyone wonders why we haven't yet updated linux process elevation for Ubuntu 18, it is because it requires a degree of low-level gymnastics we have yet to sit down and have time to revise - Windows is actually by far the worse - Mac was the easiest - Linux is somewhere inbetween!),

Also I've just overseen / architected / written a substantial portion of another project which uses a split process model to great effect - the UI is absolutely rock-solid. If the command line tool underneath throws an error (which it is, completely unavoidably, prone to do in an unfortunately large number of circumstances) the UI just carries on quite happily and just re-runs the command line tool as it needs to. (I must confess even I was quite surprised at the level of robustness of the UI when built like that - and I was the one who suggested doing it that way!)

[ I'm exceptionally proud to say the project is 95% LiveCode Script - getting on for 100,000 lines of it now - with only one very thin binary stackfile - the latter only really being important because it means we can follow the same engineering practices as we do on the engine C++ source base with zero friction! ]
If waitDepth is subject to corruption, then for the time-being I think we may have to build a manual task tree and poor-mans-semaphores to keep things straight. That may at least remove one failure mode and get us to two days between force quits.
It is important for me to note that all that I've said above *is not corruption* - corruption would suggest some sort of bug in the engine - which there is not (there might be lots of bugs still in the engine, but none in this particular case!). All behavior here is entirely deterministic and is a direct reflection of the engine's implementation with regards wait with messages.

Any apparently 'odd effects' are entirely caused by script. i.e. Either there is something in one of the scripts you have written which is interacting badly with your scheduler *or* there is a case your scheduler is perhaps not handling quite correctly.

As an example. I think Kevin has talked about the Kognition project on a few occasions (particularly at LCG) [ for those who have never heard of it, its a joint-venture we started a couple of years ago to do with 'AI' driven search of very large corpora of documents ].

I remember Kevin getting somewhat frustrated ( I've perhaps toned that down a little ;) ) in the early days of the project because it was suffering the dreaded 'recursive wait problem(s)' - basically if you sneezed at it, you'd end up with the whole Force-Quit reload scenario.

When I took a look at the code, I could see immediately what the problem was - it was using 'get url' all over the place in response to UI events (a perfectly natural thing to do, and reasonable - at least in projects which don't quite have the scale of this particular one!).

My suggested resolution was to either (a) rewrite the code using load url and callbacks (i.e. async); or (b) make sure you block the UI whenever it is doing get url so that you can't get into a recursive mess in the first place.

Eventually Kevin accepted that I wasn't going to be able to offer an immediate 'magical' engine solution (not that there are ever magical solutions - everything just comes down to having a highly-skilled, hard-working team!) and first the UI blocks were put in (i.e. a 'Waiting...' overlay); then over time they moved all the code to use async (I think there is still some 'Waiting...' overlays in it - but only in cases where its actually provides a more understandable UI experience for the user).

So in theory, if you have a script ('scheduler') which ensures the waitDepth is 1 before it allows another task in the list to start then it *should*, in theory at least, be fine. Without seeing the code / or understanding more in detail about the methods you've tried to instigate to solve the problem, it is really hard to say what the underlying issue might really be.

In reality, you can replicate precisely what 4D does with co-operative threads with just LC's message / wait model as it is right now and in a single process. The problem is that there's a fair bit of boilerplate you'd have to cookie-cut identically in a lot of places to do so, and have to divide things down into a great many smaller handlers which would end up making the code a great deal more difficult to maintain (I think I have a reasonable rough mental model of what you are doing from your description - but could be wrong - but I am pretty confident I can see precisely how 4D is implemented, under the hood).

In any case, I am mostly convinced we can model the parts of 4D's process model that you need to get the same level of abstraction offered in that tool using a script library and running a process farm with simple two-way communication using arrayEncode as the serialization mechanism. There are, as always, a fair few technical details to think through but...

It is actually a step I'd like to take for the (not Kognition) project I mentioned above. Essentially it would allow us to parallelise a number of (independent) batch phases that tool must do, which are quite slow (sometimes agonisingly so!). I can't fix the slowness of any particular phase (well that's not entirely true, I *can* fix them, but I don't have the 6-12 man months available right now to do so). However, what I can do is leverage modern multi-core processors by going back to good old UNIX where isolated child processes are often your very best and most absolute friend!

Anyway, the above is not actually Part 2, but instead:

Interlude - Dealing with @Mikey's Impatience

;)

(Indeed, it seems that @Mikey was so impatient, he thought it necessary to post his message twice! :D)

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 6236
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Multi Threadedness ?

Post by FourthWorld » Sat Aug 11, 2018 6:23 pm

LCMark wrote:
Sat Aug 11, 2018 5:57 pm
The engine already has process support (open process), it is just a bit of a pain to use in an async manner as you need to poll, rather than use 'with message' like sockets (admittedly that is just a thing which really irks me - the actual end effect is the same, the code is just less 'pretty' then it could be).
Why not use local sockets for IPC?
Richard Gaskin
Community volunteer LiveCode Community Liaison

LiveCode development, training, and consulting services: Fourth World Systems: http://FourthWorld.com
LiveCode User Group on Facebook : http://FaceBook.com/groups/LiveCodeUsers/

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 6236
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Multi Threadedness ?

Post by FourthWorld » Sat Aug 11, 2018 6:28 pm

LCMark wrote:
Sat Aug 11, 2018 5:17 am
By the way, which part in regards to async-friendliness did you want me to expand on?
Thanks. You know me: my main interests include performance, so here that would be any ways to use existing engine features more effectively to split work up among multiple processes. And for server-side work, I'm always keen on picking up tips which maximize async activity for robustly supporting more concurrent users, via workers, etc.

So far this conversation is flowing quite satisfyingly along those lines as it is. Carry on. As I have specific questions I'll ask.
Richard Gaskin
Community volunteer LiveCode Community Liaison

LiveCode development, training, and consulting services: Fourth World Systems: http://FourthWorld.com
LiveCode User Group on Facebook : http://FaceBook.com/groups/LiveCodeUsers/

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 996
Joined: Thu Apr 11, 2013 11:27 am

Re: Multi Threadedness ?

Post by LCMark » Sat Aug 11, 2018 6:38 pm

FourthWorld: Why not use local sockets for IPC?
Indeed, you can do that - you can create a socket in the parent process, then you can pass the port you get for that as an argument to the child process, the child process connects to the parent, and you can carry on your merry way... However then you have to manage two things - the 'server' side of the socket connections and the 'server' side of the open processes - in the parent.

Also, it means that your child process has to be explicitly be designed to work with a socket.

Given that processes come with a perfectly good triple of I/O end-points (stdin / stdout / stderr) for free it seems a bit wasteful not to use them - especially as you then have a mechanism which can work with any 'UNIX-style' command-line executable, and not just ones you have explicitly designed to understand the passing of a socket in the specific way you have chosen.

Now, obviously if we are talking about writing a script library which abstracts all these things, then there's no reason not to offer a socket as an option I suppose. However, it is only worth adding that extra complexity if a use-case comes up where the standard IO handles are not enough (and it would add a fair bit of extra complexity!).

Also, at heart, I dislike using OS features which potentially come with more baggage then they need to. At the kernel-level the actual way sockets and fd's (or HANDLEs if you speak WIn32-eze) work is essentially the same (in fact the very low-level atomic 'things' of which they are made out of are exactly the same!)... However, sockets hook into a number of other places - and are also globally public things. 'Pipes' (which are the things used to connect process's fd's together) are completely private to the two end-points (as far as my understanding of UNIX/Win32 OS implementations go).

To be honest, I'm not sure whether there are any security implications there or not (I suspect there are) - but I guess my approach is usually always: "only use what you need".

[ The above I guess is kind of the opposite of 'only pay for what you use' - something bandied about in the C++ world a fair bit. ]

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 6236
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Multi Threadedness ?

Post by FourthWorld » Sat Aug 11, 2018 6:55 pm

LCMark wrote:
Sat Aug 11, 2018 6:38 pm
FourthWorld: Why not use local sockets for IPC?
Indeed, you can do that - you can create a socket in the parent process, then you can pass the port you get for that as an argument to the child process, the child process connects to the parent, and you can carry on your merry way... However then you have to manage two things - the 'server' side of the socket connections and the 'server' side of the open processes - in the parent.

Also, it means that your child process has to be explicitly be designed to work with a socket.
I don't mind, if it's what's needed for message-driven multiprocessing.
Given that processes come with a perfectly good triple of I/O end-points (stdin / stdout / stderr) for free it seems a bit wasteful not to use them - especially as you then have a mechanism which can work with any command-line executable then, and not just ones you have explicitly designed to understand the passing of a socket in the specific way you have chosen.

Now, obviously if we are talking about writing a script library which abstracts all these things, then there's no reason not to offer a socket as an option I supoose. However, it is only worth adding that extra complexity if a use-case comes up where the IO handles are not enough (and it would add a fair bit of extra complexity!).
Ah, but the polling you referred to - I'm not a big fan myself; to my eye message callbacks feel clean and are easy to read/debug.

Since it seems we don't currently have message callbacks with "open process", do you feel polling would be a suitable substitute for now? What interval would you recommend? And if we open the process "for both" (I'm assuming that would be what's needed for polling) are there any downside to managing a pool of three or four workers this way?

I also prefer the fewest number of moving parts, but have thus far spent all my time doing IPC with sockets because without callbacks pipes seemed limiting. I'm glad to be mistaken on that.

Though I'm focused on what I can do with the engine we have now, it may also be helpful to plan ahead: do you foresee a specific future version in which "open process" would include callbacks?
Richard Gaskin
Community volunteer LiveCode Community Liaison

LiveCode development, training, and consulting services: Fourth World Systems: http://FourthWorld.com
LiveCode User Group on Facebook : http://FaceBook.com/groups/LiveCodeUsers/

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 996
Joined: Thu Apr 11, 2013 11:27 am

Re: Multi Threadedness ?

Post by LCMark » Sat Aug 11, 2018 11:58 pm

@FourthWorld: In not-quite reverse order (just because...)
Though I'm focused on what I can do with the engine we have now, it may also be helpful to plan ahead: do you foresee a specific future version in which "open process" would include callbacks?
Indeed - as am I - although I did mention a few posts back about 'process with message' type stuff would be quite useful, and probably only a relatively minor patch (he says, potentially optimistically!).
I also prefer the fewest number of moving parts, but have thus far spent all my time doing IPC with sockets because without callbacks pipes seemed limiting. I'm glad to be mistaken on that.
it depends on how you see them being 'limiting' really. From the point of view of achieving the goal, there isn't really much difference in terms of what the system would do (it would do exactly the same thing!).
Since it seems we don't currently have message callbacks with "open process", do you feel polling would be a suitable substitute for now?
It depends on the use-case - in particular whether the overhead to poll is actually a material factor. After all if you are farming 4 processes simultaneously which max out the CPU and take many seconds to complete - I'm not sure the tiny fraction of CPU required to run the poll loop really makes any difference at all to the speed of the resulting system.
What interval would you recommend?
And how long is that piece of string sitting over there on that imaginary rock? ;)

Again, it depends on use-case. The polling interval essentially determines the update speed of any thing managing what process is doing what in a farm. If your farm is running multi-minute processes than an interval of 1-5 seconds is probably more than sufficient. If, however, your farm is running processes which last seconds, then you'd need a polling interval less than that.

Basically, the interval determines how quickly a worker process can be 'filled up' again with work, and how quickly the results of finished computations have a visible effect.
And if we open the process "for both" (I'm assuming that would be what's needed for polling) are there any downside to managing a pool of three or four workers this way?
In principal you can farm as many as you like - of course beyond a certain number (the number of cores / hyperthreads or whatever bit of lingo the CPU manufacturers favour these days) you'll porbably be in a case of diminishing returns... Unless the operations your workers are performing are heavily I/O bound in which case most of them will be waiting more of the time anyway, so you spin up far more.

To give an example - many many years ago when Apple jumped from PPC to x86 - they omitted one rather large critical feature from Xcode... The ability to compile the exact combinations of binaries we needed - in particular PPC had to be against one SDK version, and x86 had to be against another version. There were various other things which meant I couldn't just build one arch, then the other and combine them... So I ended up writing my own high-level make description (I've always had an aversion to Make - I loathe using it!) called 'conductor' and each subcomponent had a 'score'. Anyway, conductor worked by process farming - I think I used to have it compiling with a maximum number of processes at 16 - which saturated the CPU, but still caused the compile to go faster (as compiling mostly just reads and writes files, which means there's plenty of CPU time left to do other compiling).

So, like so many other things you need empirical measurement to determine where the sweet spot is, in any given configuration.
Ah, but the polling you referred to - I'm not a big fan myself; to my eye message callbacks feel clean and are easy to read/debug.
Indeed - however, we could write a process handling library which would give you a 'with message' style API - which could use polling underneath; which diminishes the need for it to be 'in engine' for a time at least .
I don't mind, if it's what's needed for message-driven multiprocessing.
Of course your questions have reminded me that we have different use-cases for this in mind. The point here is that all you need to do this is the abstract notion of 'transport'* - i.e. the ability to queue requests for a worker process to do, pass data between host and worker in both directions, and have the child take action on the requests at appropriate points.

Either sockets or stdin etc. can do that - which is preferable depends on composition of the system, what processes you are wanting to farm, and how heavyweight (in terms of operation time) the worker processes are performing.

There's no reason you can't have both - which is used is then determined by developer-choice.

However, I'd suggest starting with the stdin etc. model - because it is a little simpler and has the advantage of being more general (i.e. it works with any command-line executable, LiveCode built, or not).

Edit: * This is not quite right - 'transport' is a lower level concept - the queuing is independent of transport, the transport is merely the mechanism by which the bytes flow between the two processes. Admittedly whether its sockets or standard handles does affect the way the queuing is implemented, and only then because sockets currently have with message, and processy stuff in LC does not. i.e. The latter is an implementation detail (albeit a somewhat important one).

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 6236
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Multi Threadedness ?

Post by FourthWorld » Sun Aug 12, 2018 3:32 am

LCMark wrote:
Sat Aug 11, 2018 11:58 pm
@FourthWorld: In not-quite reverse order (just because...)
Though I'm focused on what I can do with the engine we have now, it may also be helpful to plan ahead: do you foresee a specific future version in which "open process" would include callbacks?
Indeed - as am I - although I did mention a few posts back about 'process with message' type stuff would be quite useful, and probably only a relatively minor patch (he says, potentially optimistically!).
Given the caveat that we all need to understand that any implementation estimates discussed here informally are only loose brainstorming and should not be construed as a fixed schedule, are you in a position to venture whether callbacks for pipes would be likely in the v9 series, v10, or later?
Richard Gaskin
Community volunteer LiveCode Community Liaison

LiveCode development, training, and consulting services: Fourth World Systems: http://FourthWorld.com
LiveCode User Group on Facebook : http://FaceBook.com/groups/LiveCodeUsers/

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 996
Joined: Thu Apr 11, 2013 11:27 am

Re: Multi Threadedness ?

Post by LCMark » Mon Aug 13, 2018 10:54 am

@FourthWorld: Irksomely I wrote a response to the above then it got eaten because I had been logged out of the forums (due to timeout).

Anyway - I've reviewed the code in the engine for this and the engine change is unlikely to happen soon. However, that being said, wrapping the current functionality in a higher-level scripting library which provides 'with message' versions of open process will give the same effect without having to touch any C++.

Yes, there is a small performance negative from having a poll loop at the root, but as mentioned previously, that doesn't really make any difference for use-cases which want to farm existing shell commands (rather than ones which are built in LiveCode and so can easily use a socket instead).

My current thoughts are that it would be much more worthwhile to look at moving the engine's core I/O to use libev (node.js's core single-threaded I/O dispatch library) rather than try and modify the existing implementation - although that is definitely a project which won't be done for quite a while.

Post Reply

Return to “Feature Requests”