Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Yarko Tymciurak
On Sun, Jun 25, 2017 at 10:33 PM, Guido van Rossum 
wrote:

> On Sun, Jun 25, 2017 at 3:38 PM, Yarko Tymciurak 
> wrote:
>
>> To be a well-behaved (capable of effective cooperation) task in such a
>> system, you should guard against getting embroiled in potentially blocking
>> I/O tasks whose latency you are not able to control (within facilities
>> available in a cooperative multitasking context).  The raises a couple of
>> questions: to be well-behaved, simple control flow is desireable (i.e. not
>> nested layers of yields, except perhaps for a pipeline case); and
>> "read/write" control from memory space w/in the process (since external I/O
>> is generally not for async) begs the question: what for?  Eliminate
>> globals, encapsulate and limit access as needed through usual programming
>> methods.
>>
>
> Before anyone takes this paragraph too seriously, there seem to be a bunch
> of misunderstandings underlying this paragraph.
>

yes - thanks for the clarifications...  I'm speaking from the perspective
of an ECE, and thinking in the small-scale (embedded) of things like when
in general is cooperative multitasking (very light-weight) more performant
than pre-emptive... so from that space:

>
> - *All* blocking I/O is wrong in an async task, regardless of whether you
> can control its latency. (The only safe way to do I/O is using a primitive
> that works with `await`.)
>
> - There's nothing wrong with `yield` itself. (You shouldn't do I/O in a
> generator used in an async task -- but that's just due to the general ban
> on I/O.)
>
> - Using async tasks don't make globals more risky than regular code (in
> fact they are safer here than in traditional multi-threaded code).
>
> - What on earth is "read/write" control from memory space w/in the process?
>
> --
> --Guido van Rossum (python.org/~guido)
>
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Yarko Tymciurak
On Sun, Jun 25, 2017 at 10:46 PM, Yarko Tymciurak  wrote:

>
>
> On Sun, Jun 25, 2017 at 10:33 PM, Guido van Rossum 
> wrote:
>
>> On Sun, Jun 25, 2017 at 3:38 PM, Yarko Tymciurak 
>> wrote:
>>
>>> To be a well-behaved (capable of effective cooperation) task in such a
>>> system, you should guard against getting embroiled in potentially blocking
>>> I/O tasks whose latency you are not able to control (within facilities
>>> available in a cooperative multitasking context).  The raises a couple of
>>> questions: to be well-behaved, simple control flow is desireable (i.e. not
>>> nested layers of yields, except perhaps for a pipeline case); and
>>> "read/write" control from memory space w/in the process (since external I/O
>>> is generally not for async) begs the question: what for?  Eliminate
>>> globals, encapsulate and limit access as needed through usual programming
>>> methods.
>>>
>>
>> Before anyone takes this paragraph too seriously, there seem to be a
>> bunch of misunderstandings underlying this paragraph.
>>
>
> yes - thanks for the clarifications...  I'm speaking from the perspective
> of an ECE, and thinking in the small-scale (embedded) of things like when
> in general is cooperative multitasking (very light-weight) more performant
> than pre-emptive... so from that space:
>
>>
>> - *All* blocking I/O is wrong in an async task, regardless of whether you
>> can control its latency. (The only safe way to do I/O is using a primitive
>> that works with `await`.)
>>
>
yes, and from ECE perspective the only I/O is "local" device (e.g. RAM,
which itself has rather deterministic setup and write times...), etc.

my more general point (sorry - should have made it explicit) is that if you
call a library routine, you may not expect it's calling external I/O, so
that requires either care (or defensively guarding against it, e.g. with
timers ... another story).   This in particular is an error which I saw in
OpenStack swift project - they depended on fast local storage device I/O.
Except when devices started failing.   Then they mistakenly assumed this
was python's fault - missing the programming error of doing async (gevent -
but same issue) I/O (which might be ok, within limits, but was not guarded
against - was done in an unreliable way).

So - whether intentionally doing such "risky" but seemingly reliable and
"ok" I/O and failing to put in place guards, as must be in cooperative
multitasking, or if you just get surprised that some library you thought
was inoccuous is somewhere doing some surprise I/O (logging?
anything...) in cooperative multi-tasking, you can get away with some
things, but it is _all_ your responsibility to guard against problems.

That was my point here.


>> - There's nothing wrong with `yield` itself. (You shouldn't do I/O in a
>> generator used in an async task -- but that's just due to the general ban
>> on I/O.)
>>
>
Yes;  as above.  But I'm calling local variables (strictly speaking) I/O
too.   And you might consider REDIS as "to RAM, so how different is that?"
--- well, it's through another process, and ... up to a preemptive
scheduler, and all sorts of things.  So, sure - you _can_ do it, if you put
in guards.  But don't.  Or at least, have very specific good reasons, and
understand the coding cost of trying to do so.  In other words - don't.


>
>> - Using async tasks don't make globals more risky than regular code (in
>> fact they are safer here than in traditional multi-threaded code).
>>
>> - What on earth is "read/write" control from memory space w/in the
>> process?
>>
>
Sorry - these last two were a bit of a joke on my part.   The silly:  only
valid I/O is to variables.  But you don't need that, because you have
normal variable scoping/encapsulation rules.   So (I suppose my joke
continued), the only reason to have "read/write controls left is against
(!) global variables.  Answer - don't;  and you don'' need R/W controls,
because you have normal encapsulation controls of variables from the
language.  So - in cooperative multitasking, my argument goes, there can be
(!) no reasonable motivation for R/W controls.

-- Yarko


>
>>
>> --
>> --Guido van Rossum (python.org/~guido)
>>
>
>
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Guido van Rossum
On Sun, Jun 25, 2017 at 3:38 PM, Yarko Tymciurak  wrote:

> To be a well-behaved (capable of effective cooperation) task in such a
> system, you should guard against getting embroiled in potentially blocking
> I/O tasks whose latency you are not able to control (within facilities
> available in a cooperative multitasking context).  The raises a couple of
> questions: to be well-behaved, simple control flow is desireable (i.e. not
> nested layers of yields, except perhaps for a pipeline case); and
> "read/write" control from memory space w/in the process (since external I/O
> is generally not for async) begs the question: what for?  Eliminate
> globals, encapsulate and limit access as needed through usual programming
> methods.
>

Before anyone takes this paragraph too seriously, there seem to be a bunch
of misunderstandings underlying this paragraph.

- *All* blocking I/O is wrong in an async task, regardless of whether you
can control its latency. (The only safe way to do I/O is using a primitive
that works with `await`.)

- There's nothing wrong with `yield` itself. (You shouldn't do I/O in a
generator used in an async task -- but that's just due to the general ban
on I/O.)

- Using async tasks don't make globals more risky than regular code (in
fact they are safer here than in traditional multi-threaded code).

- What on earth is "read/write" control from memory space w/in the process?

-- 
--Guido van Rossum (python.org/~guido)
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Chris Jerdonek
So here's one approach I'm thinking about for implementing
readers-writer synchronization. Does this seem reasonable as a
starting point, or am I missing something much simpler?

I know there are various things you can prioritize for (readers vs.
writers, etc), but I'm less concerned about those for now.

The global state is--

* reader_count: an integer count of the active (reading) readers
* writer_lock: an asyncio Lock object
* no_readers_event: an asyncio Event object signaling no active readers
* no_writer_event: an asyncio Event object signaling no active writer

Untested pseudo-code for a writer--

async with writer_lock:
no_writer_event.clear()
# Wait for the readers to finish.
await no_readers_event.wait()
# Do the write.
await write()

# Awaken waiting readers.
no_writer_event.set()

Untested pseudo-code for a reader--

while True:
await no_writer_event.wait()
# Check the writer_lock again in case a new writer has
# started writing.
if not writer_lock.locked():
# Then we can do the read.
break

reader_count += 1
if reader_count == 1:
no_readers_event.clear()
# Do the read.
await read()
reader_count -= 1
if reader_count == 0:
# Awaken any waiting writer.
no_readers_event.set()

One thing I'm not clear about is when the writer_lock is released and
the no_writer_event set, are there any guarantees about what coroutine
will be awakened first -- a writer waiting on the lock or the readers
waiting on the no_writer_event?

Similarly, is there a way to avoid having to have readers check the
writer_lock again when a reader waiting on no_writer_event is
awakened?

--Chris


On Sun, Jun 25, 2017 at 3:27 PM, Chris Jerdonek
 wrote:
> On Sun, Jun 25, 2017 at 3:09 PM, Nathaniel Smith  wrote:
>> On Sun, Jun 25, 2017 at 2:13 PM, Chris Jerdonek
>>  wrote:
>>> I'm using asyncio, and the synchronization primitives that asyncio
>>> exposes are relatively simple [1]. Have options for async read-write
>>> synchronization already been discussed in any detail?
>>
>> As a general comment: I used to think rwlocks were a simple extension
>> to regular locks, but it turns out there's actually this huge increase
>> in design complexity. Do you want your lock to be read-biased,
>> write-biased, task-fair, phase-fair? Can you acquire a write lock if
>> you already hold one (i.e., are write locks reentrant)? What about
>> acquiring a read lock if you already hold the write lock? Can you
>> atomically upgrade/downgrade a lock? This makes it much harder to come
>> up with a one-size-fits-all design suitable for adding to something
>> like the python stdlib.
>
> I agree. And my point about asyncio's primitives wasn't a criticism or
> request that more be added. I was asking more if there has been any
> discussion of general approaches and patterns that take advantage of
> the event loop's single thread, etc.
>
> Maybe what I'll do is briefly write up the approach I have in mind,
> and people can let me know if I'm on the right track. :)
>
> --Chris
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Yarko Tymciurak
On Sun, Jun 25, 2017 at 4:54 PM Chris Jerdonek 
wrote:

> The read-write operations I'm protecting will have coroutines inside
> that need to be awaited on, so I don't think I'll be able to take
> advantage to that extreme.
>
> But I think I might be able to use your point to simplify the logic a
> little. (To rephrase, you're reminding me that context switches can't
> happen at arbitrary lines of code. I only need to be prepared for the
> cases where there's an await / yield from.)


The "secret" Guido refers to we should pull out front and center,
explicitly at all times - asynchronous programming is nothing more than
cooperative multitasking.

Patterns suited for preemptive multi-tasking (executive-based, interrupt
based, etc.) are suspect, potentially misplaced when they show up in a
cooperative multitasking context.

To be a well-behaved (capable of effective cooperation) task in such a
system, you should guard against getting embroiled in potentially blocking
I/O tasks whose latency you are not able to control (within facilities
available in a cooperative multitasking context).  The raises a couple of
questions: to be well-behaved, simple control flow is desireable (i.e. not
nested layers of yields, except perhaps for a pipeline case); and
"read/write" control from memory space w/in the process (since external I/O
is generally not for async) begs the question: what for?  Eliminate
globals, encapsulate and limit access as needed theough usual programming
methods.

I'm sure someone will find an edgecase to challenge my above rule-of-thumb,
but as you're new to this, I think this is a pretty good place to start.
Ask yourself if what your trying to do w/ async is suited for async.

Cheers,
Yarko

>
>
> --Chris
>
>
> On Sun, Jun 25, 2017 at 2:30 PM, Guido van Rossum 
> wrote:
> > The secret is that as long as you don't yield no other task will run so
> you
> > don't need locks at all.
> >
> > On Jun 25, 2017 2:24 PM, "Chris Jerdonek" 
> wrote:
> >>
> >> Thank you. I had seen that, but it seems heavier weight than needed.
> >> And it also requires locking on reading.
> >>
> >> --Chris
> >>
> >> On Sun, Jun 25, 2017 at 2:16 PM, Andrew Svetlov
> >>  wrote:
> >> > There is https://github.com/aio-libs/aiorwlock
> >> >
> >> > On Mon, Jun 26, 2017 at 12:13 AM Chris Jerdonek
> >> > 
> >> > wrote:
> >> >>
> >> >> I'm relatively new to async programming in Python and am thinking
> >> >> through possibilities for doing "read-write" synchronization.
> >> >>
> >> >> I'm using asyncio, and the synchronization primitives that asyncio
> >> >> exposes are relatively simple [1]. Have options for async read-write
> >> >> synchronization already been discussed in any detail?
> >> >>
> >> >> I'm interested in designs where "readers" don't need to acquire a
> lock
> >> >> -- only writers. It seems like one way to deal with the main race
> >> >> condition I see that comes up would be to use loop.time(). Does that
> >> >> ring a bell, or might there be a much simpler way?
> >> >>
> >> >> Thanks,
> >> >> --Chris
> >> >>
> >> >>
> >> >> [1] https://docs.python.org/3/library/asyncio-sync.html
> >> >> ___
> >> >> Async-sig mailing list
> >> >> Async-sig@python.org
> >> >> https://mail.python.org/mailman/listinfo/async-sig
> >> >> Code of Conduct: https://www.python.org/psf/codeofconduct/
> >> >
> >> > --
> >> > Thanks,
> >> > Andrew Svetlov
> >> ___
> >> Async-sig mailing list
> >> Async-sig@python.org
> >> https://mail.python.org/mailman/listinfo/async-sig
> >> Code of Conduct: https://www.python.org/psf/codeofconduct/
> ___
> Async-sig mailing list
> Async-sig@python.org
> https://mail.python.org/mailman/listinfo/async-sig
> Code of Conduct: https://www.python.org/psf/codeofconduct/
>
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Chris Jerdonek
On Sun, Jun 25, 2017 at 3:09 PM, Nathaniel Smith  wrote:
> On Sun, Jun 25, 2017 at 2:13 PM, Chris Jerdonek
>  wrote:
>> I'm using asyncio, and the synchronization primitives that asyncio
>> exposes are relatively simple [1]. Have options for async read-write
>> synchronization already been discussed in any detail?
>
> As a general comment: I used to think rwlocks were a simple extension
> to regular locks, but it turns out there's actually this huge increase
> in design complexity. Do you want your lock to be read-biased,
> write-biased, task-fair, phase-fair? Can you acquire a write lock if
> you already hold one (i.e., are write locks reentrant)? What about
> acquiring a read lock if you already hold the write lock? Can you
> atomically upgrade/downgrade a lock? This makes it much harder to come
> up with a one-size-fits-all design suitable for adding to something
> like the python stdlib.

I agree. And my point about asyncio's primitives wasn't a criticism or
request that more be added. I was asking more if there has been any
discussion of general approaches and patterns that take advantage of
the event loop's single thread, etc.

Maybe what I'll do is briefly write up the approach I have in mind,
and people can let me know if I'm on the right track. :)

--Chris
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Nathaniel Smith
On Sun, Jun 25, 2017 at 2:13 PM, Chris Jerdonek
 wrote:
> I'm relatively new to async programming in Python and am thinking
> through possibilities for doing "read-write" synchronization.
>
> I'm using asyncio, and the synchronization primitives that asyncio
> exposes are relatively simple [1]. Have options for async read-write
> synchronization already been discussed in any detail?

As a general comment: I used to think rwlocks were a simple extension
to regular locks, but it turns out there's actually this huge increase
in design complexity. Do you want your lock to be read-biased,
write-biased, task-fair, phase-fair? Can you acquire a write lock if
you already hold one (i.e., are write locks reentrant)? What about
acquiring a read lock if you already hold the write lock? Can you
atomically upgrade/downgrade a lock? This makes it much harder to come
up with a one-size-fits-all design suitable for adding to something
like the python stdlib.

-n

-- 
Nathaniel J. Smith -- https://vorpus.org
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Guido van Rossum
The secret is that as long as you don't yield no other task will run so you
don't need locks at all.

On Jun 25, 2017 2:24 PM, "Chris Jerdonek"  wrote:

> Thank you. I had seen that, but it seems heavier weight than needed.
> And it also requires locking on reading.
>
> --Chris
>
> On Sun, Jun 25, 2017 at 2:16 PM, Andrew Svetlov
>  wrote:
> > There is https://github.com/aio-libs/aiorwlock
> >
> > On Mon, Jun 26, 2017 at 12:13 AM Chris Jerdonek <
> chris.jerdo...@gmail.com>
> > wrote:
> >>
> >> I'm relatively new to async programming in Python and am thinking
> >> through possibilities for doing "read-write" synchronization.
> >>
> >> I'm using asyncio, and the synchronization primitives that asyncio
> >> exposes are relatively simple [1]. Have options for async read-write
> >> synchronization already been discussed in any detail?
> >>
> >> I'm interested in designs where "readers" don't need to acquire a lock
> >> -- only writers. It seems like one way to deal with the main race
> >> condition I see that comes up would be to use loop.time(). Does that
> >> ring a bell, or might there be a much simpler way?
> >>
> >> Thanks,
> >> --Chris
> >>
> >>
> >> [1] https://docs.python.org/3/library/asyncio-sync.html
> >> ___
> >> Async-sig mailing list
> >> Async-sig@python.org
> >> https://mail.python.org/mailman/listinfo/async-sig
> >> Code of Conduct: https://www.python.org/psf/codeofconduct/
> >
> > --
> > Thanks,
> > Andrew Svetlov
> ___
> Async-sig mailing list
> Async-sig@python.org
> https://mail.python.org/mailman/listinfo/async-sig
> Code of Conduct: https://www.python.org/psf/codeofconduct/
>
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Chris Jerdonek
The read-write operations I'm protecting will have coroutines inside
that need to be awaited on, so I don't think I'll be able to take
advantage to that extreme.

But I think I might be able to use your point to simplify the logic a
little. (To rephrase, you're reminding me that context switches can't
happen at arbitrary lines of code. I only need to be prepared for the
cases where there's an await / yield from.)

--Chris


On Sun, Jun 25, 2017 at 2:30 PM, Guido van Rossum  wrote:
> The secret is that as long as you don't yield no other task will run so you
> don't need locks at all.
>
> On Jun 25, 2017 2:24 PM, "Chris Jerdonek"  wrote:
>>
>> Thank you. I had seen that, but it seems heavier weight than needed.
>> And it also requires locking on reading.
>>
>> --Chris
>>
>> On Sun, Jun 25, 2017 at 2:16 PM, Andrew Svetlov
>>  wrote:
>> > There is https://github.com/aio-libs/aiorwlock
>> >
>> > On Mon, Jun 26, 2017 at 12:13 AM Chris Jerdonek
>> > 
>> > wrote:
>> >>
>> >> I'm relatively new to async programming in Python and am thinking
>> >> through possibilities for doing "read-write" synchronization.
>> >>
>> >> I'm using asyncio, and the synchronization primitives that asyncio
>> >> exposes are relatively simple [1]. Have options for async read-write
>> >> synchronization already been discussed in any detail?
>> >>
>> >> I'm interested in designs where "readers" don't need to acquire a lock
>> >> -- only writers. It seems like one way to deal with the main race
>> >> condition I see that comes up would be to use loop.time(). Does that
>> >> ring a bell, or might there be a much simpler way?
>> >>
>> >> Thanks,
>> >> --Chris
>> >>
>> >>
>> >> [1] https://docs.python.org/3/library/asyncio-sync.html
>> >> ___
>> >> Async-sig mailing list
>> >> Async-sig@python.org
>> >> https://mail.python.org/mailman/listinfo/async-sig
>> >> Code of Conduct: https://www.python.org/psf/codeofconduct/
>> >
>> > --
>> > Thanks,
>> > Andrew Svetlov
>> ___
>> Async-sig mailing list
>> Async-sig@python.org
>> https://mail.python.org/mailman/listinfo/async-sig
>> Code of Conduct: https://www.python.org/psf/codeofconduct/
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Chris Jerdonek
Thank you. I had seen that, but it seems heavier weight than needed.
And it also requires locking on reading.

--Chris

On Sun, Jun 25, 2017 at 2:16 PM, Andrew Svetlov
 wrote:
> There is https://github.com/aio-libs/aiorwlock
>
> On Mon, Jun 26, 2017 at 12:13 AM Chris Jerdonek 
> wrote:
>>
>> I'm relatively new to async programming in Python and am thinking
>> through possibilities for doing "read-write" synchronization.
>>
>> I'm using asyncio, and the synchronization primitives that asyncio
>> exposes are relatively simple [1]. Have options for async read-write
>> synchronization already been discussed in any detail?
>>
>> I'm interested in designs where "readers" don't need to acquire a lock
>> -- only writers. It seems like one way to deal with the main race
>> condition I see that comes up would be to use loop.time(). Does that
>> ring a bell, or might there be a much simpler way?
>>
>> Thanks,
>> --Chris
>>
>>
>> [1] https://docs.python.org/3/library/asyncio-sync.html
>> ___
>> Async-sig mailing list
>> Async-sig@python.org
>> https://mail.python.org/mailman/listinfo/async-sig
>> Code of Conduct: https://www.python.org/psf/codeofconduct/
>
> --
> Thanks,
> Andrew Svetlov
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] "read-write" synchronization

2017-06-25 Thread Andrew Svetlov
There is https://github.com/aio-libs/aiorwlock

On Mon, Jun 26, 2017 at 12:13 AM Chris Jerdonek 
wrote:

> I'm relatively new to async programming in Python and am thinking
> through possibilities for doing "read-write" synchronization.
>
> I'm using asyncio, and the synchronization primitives that asyncio
> exposes are relatively simple [1]. Have options for async read-write
> synchronization already been discussed in any detail?
>
> I'm interested in designs where "readers" don't need to acquire a lock
> -- only writers. It seems like one way to deal with the main race
> condition I see that comes up would be to use loop.time(). Does that
> ring a bell, or might there be a much simpler way?
>
> Thanks,
> --Chris
>
>
> [1] https://docs.python.org/3/library/asyncio-sync.html
> ___
> Async-sig mailing list
> Async-sig@python.org
> https://mail.python.org/mailman/listinfo/async-sig
> Code of Conduct: https://www.python.org/psf/codeofconduct/
>
-- 
Thanks,
Andrew Svetlov
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


[Async-sig] "read-write" synchronization

2017-06-25 Thread Chris Jerdonek
I'm relatively new to async programming in Python and am thinking
through possibilities for doing "read-write" synchronization.

I'm using asyncio, and the synchronization primitives that asyncio
exposes are relatively simple [1]. Have options for async read-write
synchronization already been discussed in any detail?

I'm interested in designs where "readers" don't need to acquire a lock
-- only writers. It seems like one way to deal with the main race
condition I see that comes up would be to use loop.time(). Does that
ring a bell, or might there be a much simpler way?

Thanks,
--Chris


[1] https://docs.python.org/3/library/asyncio-sync.html
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/