@@ -63,9 +63,6 @@ def remove(t):
63
63
64
64
# async
65
65
def gather (* aws , return_exceptions = False ):
66
- if not aws :
67
- return []
68
-
69
66
def done (t , er ):
70
67
# Sub-task "t" has finished, with exception "er".
71
68
nonlocal state
@@ -86,26 +83,39 @@ def done(t, er):
86
83
# Gather waiting is done, schedule the main gather task.
87
84
core ._task_queue .push (gather_task )
88
85
86
+ # Prepare the sub-tasks for the gather.
87
+ # The `state` variable counts the number of tasks to wait for, and can be negative
88
+ # if the gather should not run at all (because a task already had an exception).
89
89
ts = [core ._promote_to_task (aw ) for aw in aws ]
90
+ state = 0
90
91
for i in range (len (ts )):
91
- if ts [i ].state is not True :
92
- # Task is not running, gather not currently supported for this case.
92
+ if ts [i ].state is True :
93
+ # Task is running, register the callback to call when the task is done.
94
+ ts [i ].state = done
95
+ state += 1
96
+ elif not ts [i ].state :
97
+ # Task finished already.
98
+ if not isinstance (ts [i ].data , StopIteration ):
99
+ # Task finished by raising an exception.
100
+ if not return_exceptions :
101
+ # Do not run this gather at all.
102
+ state = - len (ts )
103
+ else :
104
+ # Task being waited on, gather not currently supported for this case.
93
105
raise RuntimeError ("can't gather" )
94
- # Register the callback to call when the task is done.
95
- ts [i ].state = done
96
106
97
107
# Set the state for execution of the gather.
98
108
gather_task = core .cur_task
99
- state = len (ts )
100
109
cancel_all = False
101
110
102
- # Wait for the a sub-task to need attention.
103
- gather_task .data = _Remove
104
- try :
105
- yield
106
- except core .CancelledError as er :
107
- cancel_all = True
108
- state = er
111
+ # Wait for a sub-task to need attention (if there are any to wait for).
112
+ if state > 0 :
113
+ gather_task .data = _Remove
114
+ try :
115
+ yield
116
+ except core .CancelledError as er :
117
+ cancel_all = True
118
+ state = er
109
119
110
120
# Clean up tasks.
111
121
for i in range (len (ts )):
@@ -118,8 +128,13 @@ def done(t, er):
118
128
# Sub-task ran to completion, get its return value.
119
129
ts [i ] = ts [i ].data .value
120
130
else :
121
- # Sub-task had an exception with return_exceptions==True, so get its exception.
122
- ts [i ] = ts [i ].data
131
+ # Sub-task had an exception.
132
+ if return_exceptions :
133
+ # Get the sub-task exception to return in the list of return values.
134
+ ts [i ] = ts [i ].data
135
+ elif isinstance (state , int ):
136
+ # Raise the sub-task exception, if there is not already an exception to raise.
137
+ state = ts [i ].data
123
138
124
139
# Either this gather was cancelled, or one of the sub-tasks raised an exception with
125
140
# return_exceptions==False, so reraise the exception here.
0 commit comments