"Source: Text/System/Par.text";
"Line: 3071";
"Date: Thu Jul 13 10:19:10 2023";
"Main: Fri Sep 26 14:29:19 2025";
// original file: Text/System/Par.text, line: 3071
// Example: H5E34 ()
print "Example: H5E34";
ei := GetEchoInput();
SetEchoInput(true);
// no-test
collatz := function(n)
   orign := n;
   niters := 0;
   maxval := n;
   while n gt 1 do
      n := IsEven(n) select n div 2 else 3*n + 1;
      niters +:= 1;
      maxval := Max(maxval, n);
   end while;
   // delay by 100, 200, or 300 milliseconds:
   _ := WaitForIO([] : TimeLimit := 100*Random(1,3));
   return <orign, niters, maxval>;
end function;
worker := procedure(host, port)
   S := Socket(host, port);
   ExchangeVersions(S);
   while true do
      ok, data := ReadObjectCheck(S);
      if not ok then break; end if;
      result := collatz(data);
      WriteObject(S, result);
   end while;
end procedure;
channelid := func<I | t where _,t := SocketInformation(I)>;
manager := procedure(workleft)
   server := Socket();
   host, port := Explode(SocketInformation(server));
   printf "Manager listening on port %o of %o\n", port, host;
   busy := {};
   while #workleft gt 0 or #busy gt 0 do
      ready := WaitForIO([server] cat Setseq(busy));
      idle := [ ];         // workers awaiting work
      for I in ready do
         if I eq server then    // new worker has connected
            W := WaitForConnection(I);
            printf "New worker %o joined\n", channelid(W);
            AsyncExchangeVersions(W);
            Append(~idle, W);
         else
            result := ReadObject(I);
            n, count, maxv := Explode(result);
            printf "%o: %o reached 1 (max %o) after %o iterations\n",
                channelid(I), n, maxv, count;
            Exclude(~busy, I);
            Append(~idle, I);
         end if;
      end for;
      for W in idle do
         if #workleft eq 0 then break; end if;
         data := workleft[1];
         Remove(~workleft, 1);
         AsyncWriteObject(W, data);
         AsyncReadObject(W);
         Include(~busy, W);
      end for;
   end while;
end procedure;
// manager
manager([1..10]);
// worker 1
worker("localhost", 46119);
// worker 2
worker("localhost", 46119);
SetEchoInput(ei);
