lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



On 26/9/22 13:52, Sean Conner wrote:

   There's a technique Apple uses (I forget the name) to connect to a service
with multiple IP addresses.  They attempt to connect to each one at the same
time, and which ever one connects first is the one used.  Using structured
concurrency this is trivial:


Using signal-based concurrency (assuming this is the name of a thing), and with no helper functions, would be like this:

  local function try_connect(ip, port)
     sched.signal('CONNECTED',  tcp.connect(ip, port) )
  end

  local function find_one_that_works(ips)
     local tasks = {}
     for i, ip in ipairs(ips) do
        tasks[i] = sched.run(try_connect, ip, 80)
     end
     return sched.wait('CONNECTED') -- will block until some task signals
  end

   connnectedskt = find_one_that_works({"192.168.1.10", "fc00::1:6"})


This code would work if tasks were killed on scoping out. With my library now I would have to manually kill everything in tasks before returning, or they would leak.

Jorge




	  local function connect_to(host,port,result)
	    result[host] = tcp.connect(host,port)
	  end

	  local result = {}
	  local tasks = nursery()
	  tasks:spawn(connect_to,'192.168.1.10',80,result)
	  tasks:spawn(connect_to,'fc00::1:6',80,result)
	  tasks:wait_any()

Don't you have to wait for them to complete in order to
get their results, and then use those to produce the return value or as
input to a subsequent computation?
   In the example above, we don't want to wait for all of them to complete,
we only care about one of them completing.

And if that is not the case, then I
would argue that those tasks are not essential, and could just as well be
cancelled upon issuing the return statement (which causes control flow to
leave the current scope).

If we insist on waiting for the tasks to complete whenever we leave the
scope for non-error reasons, then we also have an asymmetry/inconsistency
of behavior when leaving the scope; i.e., the fate of the tasks depends on
the precise way in which we leave the scope, which I think makes programs
harder to reason about in a way.
   My understanding of this is that when you have (at least from what I've
seen so far):

	do
	  local tasks <close> = nursury()
	  nursury:spawn(...)
	  nursury:spawn(...)
	  nursory:spawn(...)
	  -- do some other stuff, that might error
	end

   Is that the program won't leave the scope until all the spawned coroutins
have finished doing what they do, unless you have explicitly cancelled them
before you leave the scope.

   -spc