1 #![feature(test)] 2 3 extern crate test; 4 5 use std::cell::RefCell; 6 use std::future::Future; 7 use std::pin::Pin; 8 use std::task::{Context, Poll, Waker}; 9 10 use crossbeam::sync::Parker; 11 use test::Bencher; 12 13 /// Runs a future to completion on the current thread. block_on<F: Future>(future: F) -> F::Output14fn block_on<F: Future>(future: F) -> F::Output { 15 // Pin the future on the stack. 16 futures::pin_mut!(future); 17 18 thread_local! { 19 // Parker and waker associated with the current thread. 20 static CACHE: RefCell<(Parker, Waker)> = { 21 let parker = Parker::new(); 22 let unparker = parker.unparker().clone(); 23 let waker = async_task::waker_fn(move || unparker.unpark()); 24 RefCell::new((parker, waker)) 25 }; 26 } 27 28 CACHE.with(|cache| { 29 // Panic if `block_on()` is called recursively. 30 let (parker, waker) = &mut *cache.try_borrow_mut().ok().expect("recursive `block_on`"); 31 32 // Create the task context. 33 let cx = &mut Context::from_waker(&waker); 34 35 // Keep polling the future until completion. 36 loop { 37 match future.as_mut().poll(cx) { 38 Poll::Ready(output) => return output, 39 Poll::Pending => parker.park(), 40 } 41 } 42 }) 43 } 44 45 #[bench] custom_block_on_0_yields(b: &mut Bencher)46fn custom_block_on_0_yields(b: &mut Bencher) { 47 b.iter(|| block_on(Yields(0))); 48 } 49 50 #[bench] custom_block_on_10_yields(b: &mut Bencher)51fn custom_block_on_10_yields(b: &mut Bencher) { 52 b.iter(|| block_on(Yields(10))); 53 } 54 55 #[bench] custom_block_on_50_yields(b: &mut Bencher)56fn custom_block_on_50_yields(b: &mut Bencher) { 57 b.iter(|| block_on(Yields(50))); 58 } 59 60 #[bench] futures_block_on_0_yields(b: &mut Bencher)61fn futures_block_on_0_yields(b: &mut Bencher) { 62 b.iter(|| futures::executor::block_on(Yields(0))); 63 } 64 65 #[bench] futures_block_on_10_yields(b: &mut Bencher)66fn futures_block_on_10_yields(b: &mut Bencher) { 67 b.iter(|| futures::executor::block_on(Yields(10))); 68 } 69 70 #[bench] futures_block_on_50_yields(b: &mut Bencher)71fn futures_block_on_50_yields(b: &mut Bencher) { 72 b.iter(|| futures::executor::block_on(Yields(50))); 73 } 74 75 struct Yields(u32); 76 77 impl Future for Yields { 78 type Output = (); 79 poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>80 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 81 if self.0 == 0 { 82 Poll::Ready(()) 83 } else { 84 self.0 -= 1; 85 cx.waker().wake_by_ref(); 86 Poll::Pending 87 } 88 } 89 } 90