Some of my naive observations,

I like the design of "if out of threads, run on main thread".  If you run out 
of execution units, then the likely higher performance is to run on main 
instead of queueing/switching between "too many threads".  This does not 
actually guarantee that setting T. to cores -1 produces predictable performance 
because computer can be busy including other J environments that also set T. to 
cores -1 under a presumption of being the only application running.

An implication of this model is that a thread is only running one pyx at a 
time, and deleting a pyx should include the safe termination of that thread.  A 
command to at least delete all idle threads should be simple enough (main goal 
is to avoid restarting J).

A different multiprocessing model is one permitted by zeromq.  A dbms system 
running on another process maintains its state and responds to 
insert/set/delete/queries in some usable/rational sequence, where state means 
that queries are already a function of time.

The t. model is completely unsuited to thread state.  It may be possible to do 
(". t. '') 'myglobal =: f worldstatedata', but you never should.  Instead 
something like myglobal =: > f t. '' worldstatedata  is still a 
"semi-functional" approach where worldstatedata is snapshotted at time of call, 
a functional result is returned, and then a "transactional/acid" update is 
made.  No thread complexity/management/races/surprises involved because the 
result of f worldsnapshot is functional (same input = same output).

Killing a pyx is important if only to stop infinite loops/non termination, but 
also in distributed search, when some other thread has found "the solution".  
Even if a user makes the discouraged practice of assigning a global inside a 
thread, perhaps just like jbreak.bat, killing a thread/process only responds at 
some memory coherently possible point.  Killing a pyx before finished, will 
either result in no change to the global if it were the last action/update in 
the non-terminating "command", or if it was a "state toggle" (perhaps thread 
locking/access management) repeatedly called by the function, then the thread 
was already unpredictable as to the state, and like objects/classes, code needs 
a "reset toggle states" function in case of errors that cause the normal 
"resets" not to execute.  Killing a thread is an "ordinary error condition" 
that state dependence must be prepared for.

An interesting way to have t. manage state like a zeromq "service" would be to 
use the '' n parameter for managing names/state in threads.  So, if  0 T. 
'myname1 myname2' is called, then that whenever those names are used as 
arguments to functions, the function would be applied in that thread, and that 
thread "owns the data", and access to "that data" would automatically even 
without t. call, run in that thread.




On Sunday, April 10, 2022, 07:50:57 a.m. EDT, Henry Rich <[email protected]> 
wrote: 





Killing a thread is going to be a problem. What do you do with the 
values the thread was using?  They will never be freed.  You can't just 
free all the memory the thread allocated, because some of it may be 
values now being used by other threads.

My thought was that you would have to interrupt the system and use the 
debugger to force an error in the thread.  That would be as close as 
possible to killing it.

Henry Rich

On 4/9/2022 6:52 PM, 'Pascal Jasmin' via Beta wrote:
> There should probably be a T. command to delete all threads (to reset total 
> allocations without restarting J), and to "kill a pyx and stop a thread 
> running that pyx"
>
>
>
>
>
>
> On Saturday, April 9, 2022, 06:22:03 p.m. EDT, Henry Rich 
> <[email protected]> wrote:
>
>
>
>
>
> Threads can be created with options: core placement etc.  The '' is for
> future expansion
>
> Likewise, threads can execute with options; for example, maybe the
> master thread should be reserved to distribute work to the others.
>
> How many cores you use is up to you.  (I couldn't find an OS-independent
> way to decide).  JE generally does few data-dependent branches, and I
> expect it would not be a good idea to use two hyperthreads in one core;
> but you'll have to make that decision.
>
> Henry Rich
>
> On 4/9/2022 5:38 PM, 'Pascal Jasmin' via Beta wrote:
>> If I have a ryzen processor with 6 cores, 12 (intel term hypervisor) 
>> execution units should I run 0 T. '' 10-11 times to "give JE" up to that 
>> many threads?  a way to shorthand that repetition:
>>
>> taskS =. 3 : '0 T. '''' '^:
>> 10 taskS ''
>>
>> assumptions:
>> 1 T. '' returns the last task id created.
>> 2 T. '' returns a list of all task ids
>> 3 T. '' returns 0
>> 4 T. '' returns empty/i.0
>>
>> is there a future expectation to use n in t. or T. for other than '' ?  What 
>> might that be?
>>
>> t =: t.'' NB. must have convenience, if '' is constant.
>>
>>
>>       a =. i.4 10000000
>>
>>      timex '+/&:> +/"1 a'
>>
>> 0.0208033
>>
>> timex ' +/t "1 a'  NB. should just be overhead of sending 40m integers 
>> accross 4 tasks
>>
>> 0.0768311
>>
>> timex '+/&:> +/t "1 a'  NB. includes waiting for results for final sum
>>
>> 0.0935162
>>
>> I think these are good results. For an unsuitable threaded operation.  It 
>> scales by datavolume.  5gb/sec.  The gathering is quick.
>>
>>
>>
>>
>> On Saturday, April 9, 2022, 03:04:28 p.m. EDT, Henry Rich 
>> <[email protected]> wrote:
>>
>>
>>
>>
>>
>> The big news in J904 is multithreading.  J verbs can now be run in
>> different cores, sharing the J global namespaces.
>>
>> [A version of J with limited support for multithreading was revealed
>> last year by John Ference of Monument AI.  John's work was an important
>> proof of concept, but the J904 version is an independent development
>> using pthreads instead of OpenMP.  John has agreed with Jsoftware to
>> give Jsoftware access to the code and testcases used in his work.  We
>> have not used the code.]
>>
>> Two primitives support multithreading:
>>
>> (0 T. '')   creates a thread on a new core.  A thread running a verb is
>> called a /task/. Even if you don't plan to create tasks, you should
>> create threads to allow JE to use them for its own purposes.
>>
>> ([x] u t. '' y) executes ([x] <@:u y) as a task to produce a boxed
>> result.  The thread that executed t. continues to run.  But the result
>> is a special kind of box called a /pyx/.
>>
>> ['pyx' is Greek for box, and has been brought into English on occasion
>> when a word has been needed for a special box.  The most recent such
>> borrowing until now is for the box used by the Royal Mint to hold coins
>> for assay.]
>>
>> A pyx looks on the outside like any other box.  You can pass it as an
>> argument.  But as soon as you look inside it, your thread is blocked
>> until the task producing the pyx's value has completed. Then you see the
>> value, and your thread continues.
>>
>> Tasks share the global namespaces and thus can freely read, write, stomp
>> on, and delete names visible to other tasks.
>>
>> We encourage you to experiment with threads and tasks.  We are sure that
>> a layer of synchronizing primitives - semaphores, locks, and mutexes -
>> will be needed, but we would like to get practical experience with tasks
>> before we implement them.  Suggestions welcome.
>>
>> Henry Rich
>>
>>
>>
>>
>>
>>
>


-- 
This email has been checked for viruses by AVG.
https://www.avg.com

----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to