6
6
use crate :: task:: AtomicWaker ;
7
7
use alloc:: sync:: { Arc , Weak } ;
8
8
use core:: cell:: UnsafeCell ;
9
+ use core:: cmp;
9
10
use core:: fmt:: { self , Debug } ;
10
11
use core:: iter:: FromIterator ;
11
12
use core:: marker:: PhantomData ;
@@ -30,6 +31,33 @@ use self::task::Task;
30
31
mod ready_to_run_queue;
31
32
use self :: ready_to_run_queue:: { Dequeue , ReadyToRunQueue } ;
32
33
34
+ /// Constant used for a `FuturesUnordered` to determine how many times it is
35
+ /// allowed to poll underlying futures without yielding.
36
+ ///
37
+ /// A single call to `poll_next` may potentially do a lot of work before
38
+ /// yielding. This happens in particular if the underlying futures are awoken
39
+ /// frequently but continue to return `Pending`. This is problematic if other
40
+ /// tasks are waiting on the executor, since they do not get to run. This value
41
+ /// caps the number of calls to `poll` on underlying futures a single call to
42
+ /// `poll_next` is allowed to make.
43
+ ///
44
+ /// The value itself is chosen somewhat arbitrarily. It needs to be high enough
45
+ /// that amortize wakeup and scheduling costs, but low enough that we do not
46
+ /// starve other tasks for long.
47
+ ///
48
+ /// See also https://github.com/rust-lang/futures-rs/issues/2047.
49
+ ///
50
+ /// Note that using the length of the `FuturesUnordered` instead of this value
51
+ /// may cause problems if the number of futures is large.
52
+ /// See also https://github.com/rust-lang/futures-rs/pull/2527.
53
+ ///
54
+ /// Additionally, polling the same future twice per iteration may cause another
55
+ /// problem. So, when using this value, it is necessary to limit the max value
56
+ /// based on the length of the `FuturesUnordered`.
57
+ /// (e.g., `cmp::min(self.len(), YIELD_EVERY)`)
58
+ /// See also https://github.com/rust-lang/futures-rs/pull/2333.
59
+ const YIELD_EVERY : usize = 32 ;
60
+
33
61
/// A set of futures which may complete in any order.
34
62
///
35
63
/// This structure is optimized to manage a large number of futures.
@@ -383,21 +411,8 @@ impl<Fut: Future> Stream for FuturesUnordered<Fut> {
383
411
type Item = Fut :: Output ;
384
412
385
413
fn poll_next ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
386
- // Variable to determine how many times it is allowed to poll underlying
387
- // futures without yielding.
388
- //
389
- // A single call to `poll_next` may potentially do a lot of work before
390
- // yielding. This happens in particular if the underlying futures are awoken
391
- // frequently but continue to return `Pending`. This is problematic if other
392
- // tasks are waiting on the executor, since they do not get to run. This value
393
- // caps the number of calls to `poll` on underlying futures a single call to
394
- // `poll_next` is allowed to make.
395
- //
396
- // The value is the length of FuturesUnordered. This ensures that each
397
- // future is polled only once at most per iteration.
398
- //
399
- // See also https://github.com/rust-lang/futures-rs/issues/2047.
400
- let yield_every = self . len ( ) ;
414
+ // See YIELD_EVERY docs for more.
415
+ let yield_every = cmp:: min ( self . len ( ) , YIELD_EVERY ) ;
401
416
402
417
// Keep track of how many child futures we have polled,
403
418
// in case we want to forcibly yield.
0 commit comments