Threads in LC

Alex Tweedly alex at tweedly.net
Fri Jan 8 20:32:20 EST 2021


On 08/01/2021 01:51, Bob Sneidar via use-livecode wrote:
> I have thought about this a bit. If what you mean by multiprocessing is that a new process can be spawned while your app can go off and do other things and get notified later that something happened, then this is quite doable. If what you mean is that you want to make the app spawning the processes operate more efficiently by launching the same process over and over in multiple instances, then I don’t think so. At some point the parent process is going to have to get the result of each thread and do something about it.

I did something like this, but didn't spawn a new process for each 
asynch task being launched.

What I did instead was have a very general purpose 'task handler' app, 
and have multiple instances of this 'server app' running all the time; 
as long as they're not doing any task, that's a negligible "cost" in 
resources. Each instance would accept a socket connection on a different 
port (e.g. 6000, 6001, 6002, ...) and would be passed "requests" to 
handle a specific task. It would queue up multiple tasks, handle them in 
turn, and pass the result back over the connection to whichever app 
requested it.

Then there was a client library, which would handle all the "messiness" 
for the client, so the app need not be too involved. The app itself 
would simply 'start using' the library, tell it which tasks it wanted to 
be able to do (see below), and then pass in multiple requests through 
library calls. The library would determine how many task-handler apps 
were available, parcel out the requests between them, and provide the 
responses to the client (if needed).

For each task (or set of tasks) you would write a library stack, which 
would have handlers to perform the task(s), and respond.


Example (trivial and may contain typos).

(you have to imagine that generating random numbers was very time 
consuming :-),

1. Write a library stack to perform some tasks.

stack "randomstuff"
global gResultData, gResultObject   -- remember - one task at a time, so 
no race conditions

on randomint pData
    local tmp, tMin, tMax
    put word 1 of pData into tMin
    put word 2 of pData into tMax
    put random(tMax - tMin + 1) into tmp
    put tmp-1 + tMin into gResultData
    send "completedTask" to gResultObject in 1 millisec
end randomint


2. In the client app, determine the tasks to be handled

(within, say, openstack)
....
    taskClientLoadStack "randomstuff.livecodescript"
....

3. when you need a number of random integers
....
   repeat 1000 times
     put taskClientSendARequest("randomstuff", "randomint 12 17", the 
long ID of me) into tmp
   end repeat
    -- (the return value is a request id - often can be ignored).
...
on taskcomplete pID, pResult
    -- pID is the request ID, pResult is the returned data from that request
    put pResult &CR after sNumbers   -- or whatever
...
end taskcomplete

In addition, there were various 'admin' taks you could request (close 
connection, cancel pending tasks, get count of remaining tasks pending, 
...). The initial version of the client library simply round-robined the 
task requests between the task-handlers, but the 'status' request would 
allow for more intelligent load-balancing i fneeded.


I did all this many years ago (2006 ??) and had this up on the earliest 
version of revonline (which subsequently got deleted). I developed it to 
help with indexing (including md5hash) of large numbers of image files. 
Using 4 task handlers, it was able to do the indexing in around 1/3 of 
the time the single-threaded version took.

I still have the code - but unfortunately I can't find the write-up / 
documentation on how to use it. And, I admit I absolutely cringe now to 
look at the code - it *seriously* needs to be re-written, or heavily 
revised.

I'll clean up the code, write up how to use it and post it somewhere for 
anyone who wishes to try it out.

Alex.



More information about the use-livecode mailing list