Skip to content

Instantly share code, notes, and snippets.

@nitori
Last active May 24, 2024 16:42
Show Gist options
  • Save nitori/2668ef7f5e0f8e94fbb40122360a9791 to your computer and use it in GitHub Desktop.
Save nitori/2668ef7f5e0f8e94fbb40122360a9791 to your computer and use it in GitHub Desktop.
Possible way to combine pygame and asyncio
import asyncio
import threading
import pygame
USER_EV1 = pygame.event.custom_type()
def pygame_loop(async_stopper):
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
while True:
delta = clock.tick(60) / 1000
for event in pygame.event.get():
if event.type == pygame.QUIT:
async_stopper()
return
if event.type == USER_EV1:
print('Event data from async task:', event.dict)
screen.fill((0, 0, 64))
pygame.display.flip()
async def some_async_producer():
n = 0
while True:
await asyncio.sleep(1)
print('sleepy...')
n += 1
if n % 5 == 0:
pygame.event.post(pygame.event.Event(USER_EV1, {'foo': 'bar'}))
async def main():
# setup pygame thread
stop_event = asyncio.Event()
loop = asyncio.get_running_loop()
def _async_stopper():
loop.call_soon_threadsafe(stop_event.set)
t = threading.Thread(target=pygame_loop, args=(_async_stopper,))
t.start()
# start some background tasks.
# Could be done any other way, but just putting the "workers" into
# background makes the next steps easier
bg_tasks = [
asyncio.create_task(some_async_producer()),
]
# wait for pygame thread to stop
await stop_event.wait()
# cancel all tasks.
for task in bg_tasks:
task.cancel()
# await the cancelled tasks. No TimeoutError raised
# pending will contain remaining tasks, that failed to stop after timeout.
done, pending = await asyncio.wait(bg_tasks, timeout=5)
if len(pending) > 0:
for task in pending:
print(task, ' failed to cancel!')
loop.stop() # last resort, could probably just do sys.exit() as well
if __name__ == '__main__':
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment