2432
|
1 import asyncio
|
2454
|
2 import sys
|
|
3 from threading import Thread, get_ident
|
|
4 import time
|
2432
|
5 from typing import Coroutine
|
|
6
|
|
7
|
2454
|
8 def log(msg):
|
|
9 try:
|
|
10 rl = hex(id(asyncio.get_running_loop()))
|
|
11 except RuntimeError:
|
|
12 rl = '(no loop ----)'
|
|
13 sys.stderr.write(f"thread={hex(get_ident())} loop={rl} {msg}\n")
|
|
14
|
|
15
|
2432
|
16 def startLoopInThread(task: Coroutine) -> asyncio.AbstractEventLoop:
|
2454
|
17 """
|
|
18 run a new event loop in a background thread. `task` is run in the new loop.
|
|
19 Caller should use this (from fg thread) to run further tasks:
|
|
20 asyncio.run_coroutine_threadsafe(task, returned_loop)
|
2432
|
21
|
2454
|
22 """
|
|
23 log('🚋4 startLoopInThread enter ')
|
|
24 loops = []
|
|
25
|
|
26 def start_background_loop() -> None:
|
|
27
|
|
28 async def forever():
|
|
29 log('🚋6 log_loop')
|
|
30 loops.append(asyncio.get_running_loop())
|
|
31 while True:
|
|
32 await asyncio.sleep(100)
|
2432
|
33
|
2454
|
34 log('🚋5 make asyncio loop')
|
|
35 asyncio.run(forever())
|
|
36 log('🚋19 start_background_loop done')
|
|
37
|
|
38 t = Thread(target=start_background_loop, daemon=True)
|
2432
|
39 t.start()
|
2454
|
40 while not loops:
|
|
41 time.sleep(.1)
|
|
42 loop = loops[0]
|
|
43 log('🚋7 loop has started in thread')
|
|
44
|
2432
|
45 asyncio.run_coroutine_threadsafe(task, loop)
|
2454
|
46 log('🚋8 started task')
|
|
47
|
|
48 log('🚋9 startLoopInThread exit')
|
2432
|
49 return loop
|