@@ -112,6 +112,13 @@ struct Core {
112112 /// Used to schedule bookkeeping tasks every so often.
113113 tick : u32 ,
114114
115+ /// When a task is scheduled from a worker, it is stored in this slot. The
116+ /// worker will check this slot for a task **before** checking the run
117+ /// queue. This effectively results in the **last** scheduled task to be run
118+ /// next (LIFO). This is an optimization for improving locality which
119+ /// benefits message passing patterns and helps to reduce latency.
120+ lifo_slot : Option < Notified > ,
121+
115122 /// When `true`, locally scheduled tasks go to the LIFO slot. When `false`,
116123 /// they go to the back of the `run_queue`.
117124 lifo_enabled : bool ,
@@ -282,6 +289,7 @@ pub(super) fn create(
282289
283290 cores. push ( Box :: new ( Core {
284291 tick : 0 ,
292+ lifo_slot : None ,
285293 lifo_enabled : !config. disable_lifo_slot ,
286294 run_queue,
287295 #[ cfg( all( tokio_unstable, feature = "time" ) ) ]
@@ -443,7 +451,7 @@ where
443451 // If we heavily call `spawn_blocking`, there might be no available thread to
444452 // run this core. Except for the task in the lifo_slot, all tasks can be
445453 // stolen, so we move the task out of the lifo_slot to the run_queue.
446- if let Some ( task) = core. run_queue . pop_lifo ( ) {
454+ if let Some ( task) = core. lifo_slot . take ( ) {
447455 core. run_queue
448456 . push_back_or_overflow ( task, & * cx. worker . handle , & mut core. stats ) ;
449457 }
@@ -696,7 +704,7 @@ impl Context {
696704 } ;
697705
698706 // Check for a task in the LIFO slot
699- let task = match core. run_queue . pop_lifo ( ) {
707+ let task = match core. lifo_slot . take ( ) {
700708 Some ( task) => task,
701709 None => {
702710 self . reset_lifo_enabled ( & mut core) ;
@@ -1122,7 +1130,7 @@ impl Core {
11221130 }
11231131
11241132 fn next_local_task ( & mut self ) -> Option < Notified > {
1125- self . run_queue . pop_lifo ( ) . or_else ( || self . run_queue . pop ( ) )
1133+ self . lifo_slot . take ( ) . or_else ( || self . run_queue . pop ( ) )
11261134 }
11271135
11281136 /// Function responsible for stealing tasks from another worker
@@ -1178,7 +1186,7 @@ impl Core {
11781186 }
11791187
11801188 fn has_tasks ( & self ) -> bool {
1181- self . run_queue . has_tasks ( )
1189+ self . lifo_slot . is_some ( ) || self . run_queue . has_tasks ( )
11821190 }
11831191
11841192 fn should_notify_others ( & self ) -> bool {
@@ -1187,7 +1195,7 @@ impl Core {
11871195 if self . is_searching {
11881196 return false ;
11891197 }
1190- self . run_queue . len ( ) > 1
1198+ self . lifo_slot . is_some ( ) as usize + self . run_queue . len ( ) > 1
11911199 }
11921200
11931201 /// Prepares the worker state for parking.
@@ -1349,23 +1357,29 @@ impl Handle {
13491357 // task must always be pushed to the back of the queue, enabling other
13501358 // tasks to be executed. If **not** a yield, then there is more
13511359 // flexibility and the task may go to the front of the queue.
1352- if is_yield || !core. lifo_enabled {
1360+ let should_notify = if is_yield || !core. lifo_enabled {
13531361 core. run_queue
13541362 . push_back_or_overflow ( task, self , & mut core. stats ) ;
1363+ true
13551364 } else {
13561365 // Push to the LIFO slot
1357- if let Some ( prev) = core. run_queue . push_lifo ( task) {
1358- // There was a previous task in the LIFO slot which needs
1359- // to be pushed to the back of the run queue.
1366+ let prev = core. lifo_slot . take ( ) ;
1367+ let ret = prev. is_some ( ) ;
1368+
1369+ if let Some ( prev) = prev {
13601370 core. run_queue
13611371 . push_back_or_overflow ( prev, self , & mut core. stats ) ;
13621372 }
1373+
1374+ core. lifo_slot = Some ( task) ;
1375+
1376+ ret
13631377 } ;
13641378
13651379 // Only notify if not currently parked. If `park` is `None`, then the
13661380 // scheduling is from a resource driver. As notifications often come in
13671381 // batches, the notification is delayed until the park is complete.
1368- if core. park . is_some ( ) {
1382+ if should_notify && core. park . is_some ( ) {
13691383 self . notify_parked_local ( ) ;
13701384 }
13711385 }
0 commit comments