kopia lustrzana https://github.com/peterhinch/micropython-samples
69 wiersze
2.4 KiB
Python
69 wiersze
2.4 KiB
Python
![]() |
try:
|
||
|
import uasyncio as asyncio
|
||
|
except ImportError:
|
||
|
import asyncio
|
||
|
|
||
|
from . import launch
|
||
|
|
||
|
# A Barrier synchronises N coros. Each issues await barrier.
|
||
|
# Execution pauses until all other participant coros are waiting on it.
|
||
|
# At that point the callback is executed. Then the barrier is 'opened' and
|
||
|
# execution of all participants resumes.
|
||
|
|
||
|
# The nowait arg is to support task cancellation. It enables usage where one or
|
||
|
# more coros can register that they have reached the barrier without waiting
|
||
|
# for it. Any coros waiting normally on the barrier will pause until all
|
||
|
# non-waiting coros have passed the barrier and all waiting ones have reached
|
||
|
# it. The use of nowait promotes efficiency by enabling tasks which have been
|
||
|
# cancelled to leave the task queue as soon as possible.
|
||
|
|
||
|
class Barrier():
|
||
|
def __init__(self, participants, func=None, args=()):
|
||
|
self._participants = participants
|
||
|
self._func = func
|
||
|
self._args = args
|
||
|
self._reset(True)
|
||
|
|
||
|
def __await__(self):
|
||
|
self._update()
|
||
|
if self._at_limit(): # All other threads are also at limit
|
||
|
if self._func is not None:
|
||
|
launch(self._func, self._args)
|
||
|
self._reset(not self._down) # Toggle direction to release others
|
||
|
return
|
||
|
|
||
|
direction = self._down
|
||
|
while True: # Wait until last waiting thread changes the direction
|
||
|
if direction != self._down:
|
||
|
return
|
||
|
await asyncio.sleep_ms(0)
|
||
|
|
||
|
__iter__ = __await__
|
||
|
|
||
|
def trigger(self):
|
||
|
self._update()
|
||
|
if self._at_limit(): # All other threads are also at limit
|
||
|
if self._func is not None:
|
||
|
launch(self._func, self._args)
|
||
|
self._reset(not self._down) # Toggle direction to release others
|
||
|
|
||
|
def _reset(self, down):
|
||
|
self._down = down
|
||
|
self._count = self._participants if down else 0
|
||
|
|
||
|
def busy(self):
|
||
|
if self._down:
|
||
|
done = self._count == self._participants
|
||
|
else:
|
||
|
done = self._count == 0
|
||
|
return not done
|
||
|
|
||
|
def _at_limit(self): # Has count reached up or down limit?
|
||
|
limit = 0 if self._down else self._participants
|
||
|
return self._count == limit
|
||
|
|
||
|
def _update(self):
|
||
|
self._count += -1 if self._down else 1
|
||
|
if self._count < 0 or self._count > self._participants:
|
||
|
raise ValueError('Too many tasks accessing Barrier')
|