11import asyncio
22from collections import defaultdict
33from collections .abc import Callable
4- from concurrent .futures import Future
54from types import MethodType
65
76from softioc .asyncio_dispatcher import AsyncioDispatcher
@@ -21,7 +20,7 @@ def __init__(
2120 self ._controller = controller
2221
2322 self ._initial_tasks = [controller .connect ]
24- self ._scan_tasks : list [Future ] = []
23+ self ._scan_tasks : list [asyncio . Task ] = []
2524
2625 asyncio .run_coroutine_threadsafe (
2726 self ._controller .initialise (), self ._loop
@@ -41,22 +40,31 @@ def _link_process_tasks(self):
4140 _link_single_controller_put_tasks (single_mapping )
4241 _link_attribute_sender_class (single_mapping )
4342
43+ def __del__ (self ):
44+ self .stop_scan_tasks ()
45+
4446 def run (self ):
4547 self ._run_initial_tasks ()
46- self ._start_scan_tasks ()
47-
48+ self .start_scan_tasks ()
4849 self ._run ()
4950
5051 def _run_initial_tasks (self ):
5152 for task in self ._initial_tasks :
5253 future = asyncio .run_coroutine_threadsafe (task (), self ._loop )
5354 future .result ()
5455
55- def _start_scan_tasks (self ):
56- scan_tasks = _get_scan_tasks (self ._mapping )
56+ def start_scan_tasks (self ):
57+ self ._scan_tasks = [
58+ self ._loop .create_task (coro ()) for coro in _get_scan_coros (self ._mapping )
59+ ]
5760
58- for task in scan_tasks :
59- asyncio .run_coroutine_threadsafe (task (), self ._loop )
61+ def stop_scan_tasks (self ):
62+ for task in self ._scan_tasks :
63+ if not task .done ():
64+ try :
65+ task .cancel ()
66+ except asyncio .CancelledError :
67+ pass
6068
6169 def _run (self ):
6270 raise NotImplementedError ("Specific Backend must implement _run" )
@@ -98,15 +106,15 @@ async def callback(value):
98106 return callback
99107
100108
101- def _get_scan_tasks (mapping : Mapping ) -> list [Callable ]:
109+ def _get_scan_coros (mapping : Mapping ) -> list [Callable ]:
102110 scan_dict : dict [float , list [Callable ]] = defaultdict (list )
103111
104112 for single_mapping in mapping .get_controller_mappings ():
105113 _add_scan_method_tasks (scan_dict , single_mapping )
106114 _add_attribute_updater_tasks (scan_dict , single_mapping )
107115
108- scan_tasks = _get_periodic_scan_tasks (scan_dict )
109- return scan_tasks
116+ scan_coros = _get_periodic_scan_coros (scan_dict )
117+ return scan_coros
110118
111119
112120def _add_scan_method_tasks (
@@ -144,18 +152,18 @@ async def callback():
144152 return callback
145153
146154
147- def _get_periodic_scan_tasks (scan_dict : dict [float , list [Callable ]]) -> list [Callable ]:
148- periodic_scan_tasks : list [Callable ] = []
155+ def _get_periodic_scan_coros (scan_dict : dict [float , list [Callable ]]) -> list [Callable ]:
156+ periodic_scan_coros : list [Callable ] = []
149157 for period , methods in scan_dict .items ():
150- periodic_scan_tasks .append (_create_periodic_scan_task (period , methods ))
158+ periodic_scan_coros .append (_create_periodic_scan_coro (period , methods ))
151159
152- return periodic_scan_tasks
160+ return periodic_scan_coros
153161
154162
155- def _create_periodic_scan_task (period , methods : list [Callable ]) -> Callable :
156- async def scan_task () -> None :
163+ def _create_periodic_scan_coro (period , methods : list [Callable ]) -> Callable :
164+ async def scan_coro () -> None :
157165 while True :
158166 await asyncio .gather (* [method () for method in methods ])
159167 await asyncio .sleep (period )
160168
161- return scan_task
169+ return scan_coro
0 commit comments