结合源码理解tokio

简单总结:
初始tokio,初始化线程池(也就是worker),添加了2个future(1个是accept连接的,1个是shutdown清理的)
接受到连接后,执行回调,如果spawn了新的future,就会添加到线程池的全局任务队列,工作线程做完了任务会从全局任务队列批量偷取任务来做
简单来说就是单事件循环+线程池的模型

从tokio示例开始

extern crate tokio;

use tokio::prelude::*;
use tokio::io::copy;
use tokio::net::TcpListener;

fn main() {
    // Bind the server's socket.
    let addr = "127.0.0.1:12345".parse().unwrap();
    let listener = TcpListener::bind(&addr)
        .expect("unable to bind TCP listener");

    // Pull out a stream of sockets for incoming connections
    let server = listener.incoming()
        .map_err(|e| eprintln!("accept failed = {:?}", e))
        .for_each(|sock| {
            // Split up the reading and writing parts of the
            // socket.
            let (reader, writer) = sock.split();

            // A future that echos the data and returns how
            // many bytes were copied...
            let bytes_copied = copy(reader, writer);

            // ... after which we'll print what happened.
            let handle_conn = bytes_copied.map(|amt| {
                println!("wrote {:?} bytes", amt)
            }).map_err(|err| {
                eprintln!("IO error {:?}", err)
            });

            // Spawn the future as a concurrent task.
            tokio::spawn(handle_conn)
        });

    // Start the Tokio runtime
    tokio::run(server);
}

相关代码
TcpListener中

    pub fn incoming(self) -> Incoming {
        Incoming::new(self)
    }

impl Stream for Incoming {
    type Item = TcpStream;
    type Error = io::Error;

    fn poll(&mut self) -> Poll, io::Error> {
        let (socket, _) = try_ready!(self.inner.poll_accept());
        Ok(Async::Ready(Some(socket)))
    }
}

    fn for_each(self, f: F) -> ForEach
        where F: FnMut(Self::Item) -> U,
              U: IntoFuture,
              Self: Sized
    {
        for_each::new(self, f)
    }

pub fn new(s: S, f: F) -> ForEach
    where S: Stream,
          F: FnMut(S::Item) -> U,
          U: IntoFuture,
{
    ForEach {
        stream: s,
        f: f,
        fut: None,
    }
}

impl Future for ForEach
    where S: Stream,
          F: FnMut(S::Item) -> U,
          U: IntoFuture,
{
    type Item = ();
    type Error = S::Error;

    fn poll(&mut self) -> Poll<(), S::Error> {
        loop {
            if let Some(mut fut) = self.fut.take() {
                if fut.poll()?.is_not_ready() {
                    self.fut = Some(fut);
                    return Ok(Async::NotReady);
                }
            }

            match try_ready!(self.stream.poll()) {
                Some(e) => self.fut = Some((self.f)(e).into_future()),
                None => return Ok(Async::Ready(())),
            }
        }
    }
}

从上面可以看到,incoming返回Incoming包装后的lisntener,
而incoming实现了stream trait,就拥有了for_each方法,
for_each返回for_each包装后的incoming,
而for_each实现了Future trait, 这个是futures的关键
executor会调用poll,这个时候返回Ok(Async::NotReady),Ok(Async::Ready(()));或者Err(Error()),
从for_each的如下代码回溯

 match try_ready!(self.stream.poll()) {
其实调用了
 pub fn poll_accept(&mut self) -> Poll<(TcpStream, SocketAddr), io::Error> {
        let (io, addr) = try_ready!(self.poll_accept_std());

        let io = mio::net::TcpStream::from_stream(io)?;
        let io = TcpStream::new(io);

        Ok((io, addr).into())
    }

  pub fn poll_accept_std(&mut self) -> Poll<(net::TcpStream, SocketAddr), io::Error> {
        try_ready!(self.io.poll_read_ready(mio::Ready::readable()));

        match self.io.get_ref().accept_std() {
            Ok(pair) => Ok(pair.into()),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                self.io.clear_read_ready(mio::Ready::readable())?;
                Ok(Async::NotReady)
            }
            Err(e) => Err(e),
        }
    }

而下层其实就是mio针对epoll,kqueue等的封装

从for_each的如下代码回溯

        if let Some(mut fut) = self.fut.take() {
              if fut.poll()?.is_not_ready() {
                  self.fut = Some(fut);
                  return Ok(Async::NotReady);
              }
          }

其实就是调用示例中的
// Split up the reading and writing parts of the
          // socket.
          let (reader, writer) = sock.split();

          // A future that echos the data and returns how
          // many bytes were copied...
          let bytes_copied = copy(reader, writer);

          // ... after which we'll print what happened.
          let handle_conn = bytes_copied.map(|amt| {
              println!("wrote {:?} bytes", amt)
          }).map_err(|err| {
              eprintln!("IO error {:?}", err)
          });

          // Spawn the future as a concurrent task.

          tokio::spawn(handle_conn)

spawn前面的代码其实就是在创建future
而spawn就是把future提交到当前线程,
继续看tokio::spawn
tokio中

pub fn spawn(f: F) -> Spawn
where F: Future + 'static + Send
{
    ::tokio_executor::spawn(f);
    Spawn(())
}
 
pub fn spawn(future: T)
where
    T: Future + Send + 'static,
{
    DefaultExecutor::current().spawn(Box::new(future)).unwrap()
}

    pub fn current() -> DefaultExecutor {
        DefaultExecutor { _dummy: () }
    }

    #[inline]
    fn with_current R, R>(f: F) -> Option {
        EXECUTOR.with(
            |current_executor| match current_executor.replace(State::Active) {
                State::Ready(executor_ptr) => {
                    let executor = unsafe { &mut *executor_ptr };
                    let result = f(executor);
                    current_executor.set(State::Ready(executor_ptr));
                    Some(result)
                }
                State::Empty | State::Active => None,
            },
        )
    }

impl super::Executor for DefaultExecutor {
    fn spawn(
        &mut self,
        future: Box + Send>,
    ) -> Result<(), SpawnError> {
        DefaultExecutor::with_current(|executor| executor.spawn(future))
            .unwrap_or_else(|| Err(SpawnError::shutdown()))
    }


}

thread_local! {
    /// Thread-local tracking the current executor
    static EXECUTOR: Cell = Cell::new(State::Empty)
}

从上看到这个executor是个tls变量,存储着executor,有他来spawn future

tokio::run之前就是构建一个future,接着看tokio::run

/// [mod]: ../index.html
pub fn run(future: F)
where F: Future + Send + 'static,
{
    // Check enter before creating a new Runtime...
    let mut entered = enter().expect("nested tokio::run");
    let mut runtime = Runtime::new().expect("failed to start new Runtime");
    runtime.spawn(future);
    entered
        .block_on(runtime.shutdown_on_idle())
        .expect("shutdown cannot error")
}

继续看runtime的创建,

   pub fn new() -> io::Result {
        Builder::new().build()
    }

    pub fn new() -> Builder {
        let core_threads = num_cpus::get().max(1);

        let mut threadpool_builder = ThreadPoolBuilder::new();
        threadpool_builder.name_prefix("tokio-runtime-worker-");
        threadpool_builder.pool_size(core_threads);

        Builder {
            threadpool_builder,
            core_threads,
            clock: Clock::new(),
        }
    }

pub fn build(&mut self) -> io::Result {
...
    let pool = self
            .threadpool_builder
            .around_worker(move |w, enter| {
                let index = w.id().to_usize();

                tokio_reactor::with_default(&reactor_handles[index], enter, |enter| {
                    clock::with_default(&clock, enter, |enter| {
                        timer::with_default(&timer_handles[index], enter, |_| {
                            trace::dispatcher::with_default(&dispatch, || {
                                w.run();
                            })
                        });
                    })
                });
            })
            .custom_park(move |worker_id| {
                let index = worker_id.to_usize();

                timers[index]
                    .lock()
                    .unwrap()
                    .take()
                    .unwrap()
            })
            .build();
...

    }

pub fn with_default(handle: &Handle, enter: &mut Enter, f: F) -> R
where
    F: FnOnce(&mut Enter) -> R,
{
    // Ensure that the executor is removed from the thread-local context
    // when leaving the scope. This handles cases that involve panicking.
    struct Reset;

    impl Drop for Reset {
        fn drop(&mut self) {
            CURRENT_REACTOR.with(|current| {
                let mut current = current.borrow_mut();
                *current = None;
            });
        }
    }

    // This ensures the value for the current reactor gets reset even if there
    // is a panic.
    let _r = Reset;

    CURRENT_REACTOR.with(|current| {
        {
            let mut current = current.borrow_mut();

            assert!(
                current.is_none(),
                "default Tokio reactor already set \
                 for execution context"
            );

            let handle = match handle.as_priv() {
                Some(handle) => handle,
                None => {
                    panic!("`handle` does not reference a reactor");
                }
            };

            *current = Some(handle.clone());
        }

        f(enter)
    })
}

接着看 runtime.spawn(future);

   pub fn spawn(&self, future: F) -> &Self
    where F: Future + Send + 'static,
    {
        self.inner().pool.spawn(future);
        self
    }


    pub fn spawn(&self, future: F)
    where
        F: Future + Send + 'static,
    {
        self.sender().spawn(future).unwrap();
    }

   pub fn spawn(&self, future: F) -> Result<(), SpawnError>
    where
        F: Future + Send + 'static,
    {
        let mut s = self;
        tokio_executor::Executor::spawn(&mut s, Box::new(future))
    }



impl Executor for Box {
    fn spawn(
        &mut self,
        future: Box + Send>,
    ) -> Result<(), SpawnError> {
        (**self).spawn(future)
    }

    fn status(&self) -> Result<(), SpawnError> {
        (**self).status()
    }
}


  fn spawn(
        &mut self,
        future: Box + Send>,
    ) -> Result<(), SpawnError> {
        self.prepare_for_spawn()?;

        // At this point, the pool has accepted the future, so schedule it for
        // execution.

        // Create a new task for the future
        let task = Arc::new(Task::new(future));

        // Call `submit_external()` in order to place the task into the global
        // queue. This way all workers have equal chance of running this task,
        // which means IO handles will be assigned to reactors more evenly.
        self.pool.submit_external(task, &self.pool);

        Ok(())
    }

    pub fn submit_external(&self, task: Arc, pool: &Arc) {
        debug_assert_eq!(*self, **pool);

        trace!("    -> submit external");

        self.queue.push(task);
        self.signal_work(pool);
    }
   pub fn signal_work(&self, pool: &Arc) {
        debug_assert_eq!(*self, **pool);

        use crate::worker::Lifecycle::Signaled;

        if let Some((idx, worker_state)) = self.sleep_stack.pop(&self.workers, Signaled, false) {
            let entry = &self.workers[idx];

            debug_assert!(
                worker_state.lifecycle() != Signaled,
                "actual={:?}",
                worker_state.lifecycle(),
            );

            trace!("signal_work -- notify; idx={}", idx);

            if !entry.notify(worker_state) {
                trace!("signal_work -- spawn; idx={}", idx);
                self.spawn_thread(WorkerId(idx), pool);
            }
        }
    }

    pub fn spawn_thread(&self, id: WorkerId, pool: &Arc) {
...
let res = th.spawn(move || {
...
 loop {
...
        let worker = Worker::new(worker_id, backup_id, pool.clone(), trigger.clone());

                // Run the worker. If the worker transitioned to a "blocking"
                // state, then `is_blocking` will be true.
                if !worker.do_run() {
                    // The worker shutdown, so exit the thread.
                    break;
                }
...
}
...
}

pub(crate) fn do_run(&self) -> bool {
...
       CURRENT_WORKER.with(|c| {
            c.set(self as *const _);

            let pool = self.pool.clone();
            let mut sender = Sender { pool };

            // Enter an execution context
            let mut enter = tokio_executor::enter().unwrap();

            tokio_executor::with_default(&mut sender, &mut enter, |enter| {
                if let Some(ref callback) = self.pool.config.around_worker {
                    callback.call(self, enter);
                } else {
                    self.run();
                }
            });
        });
...
}

pub fn run(&self) {
...
     if !self.sleep() {
                return;
            }
...
}
    fn sleep(&self) -> bool {
...
        self.sleep_light();

...
}

 fn sleep_light(&self) {
        self.entry().park_timeout(Duration::from_millis(0));

        use crossbeam_deque::Steal;
        loop {
            match self.pool.queue.steal_batch(&self.entry().worker) {
                Steal::Success(()) => {
                    self.pool.signal_work(&self.pool);
                    break;
                }
                Steal::Empty => break,
                Steal::Retry => {}
            }
        }
    }

可以看到其实是吧future包装成task,然后提交到线程池中,然后通知他工作,如果通知失败,就开启新的线程

接着看runtime.shutdown_on_idle()

 pub fn shutdown_on_idle(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();
        let inner = inner.pool.shutdown_on_idle();
        Shutdown { inner }
    }




impl Future for Shutdown {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        try_ready!(self.inner.poll());
        Ok(().into())
    }
}

pool shutdown

  pub fn shutdown_on_idle(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();
        inner.sender.pool.shutdown(false, false);
        Shutdown::new(&inner.trigger)
    }

impl Shutdown {
    pub(crate) fn new(trigger: &ShutdownTrigger) -> Shutdown {
        Shutdown {
            inner: trigger.inner.clone(),
        }
    }
}
impl Future for Shutdown {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        let inner = self.inner.lock().unwrap();

        if !inner.completed {
            inner.task.register();
            Ok(Async::NotReady)
        } else {
            Ok(().into())
        }
    }
}

接下来就是futures的代码了

 pub fn register(&self) {
        self.register_task(super::current());
    }
pub fn current() -> Task {
    with(|borrowed| {
        let unpark = borrowed.unpark.to_owned();
        let events = borrowed.events.to_owned();

        Task {
            id: borrowed.id,
            unpark: unpark,
            events: events,
        }
    })
}

fn with R, R>(f: F) -> R {
    unsafe {
        let task = get_ptr().expect("no Task is currently running");
        assert!(!task.is_null(), "no Task is currently running");
        f(&*(task as *const BorrowedTask))
    }
}

pub fn get_ptr() -> Option<*mut u8> {
    // Since this condition will always return true when TLS task storage is
    // used (the default), the branch predictor will be able to optimize the
    // branching and a dynamic dispatch will be avoided, which makes the
    // compiler happier.
    if core::is_get_ptr(0x1) {
        Some(CURRENT_TASK.with(|c| c.get()))
    } else {
        core::get_ptr()
    }
}

接着看entered.block_on

pub fn block_on(&mut self, f: F) -> Result {
        futures::executor::spawn(f).wait_future()
    }

接下来就是进入futures的代码了


pub fn spawn(obj: T) -> Spawn {
    Spawn {
        id: fresh_task_id(),
        obj: obj,
        data: local_map(),
    }
}

    pub fn wait_future(&mut self) -> Result {
        ThreadNotify::with_current(|notify| {

            loop {
                match self.poll_future_notify(notify, 0)? {
                    Async::NotReady => notify.park(),
                    Async::Ready(e) => return Ok(e),
                }
            }
        })
    }

    pub fn poll_future_notify(&mut self,
                                 notify: &N,
                                 id: usize) -> Poll
        where N: Clone + Into,
              T: Future,
    {
        self.poll_fn_notify(notify, id, |f| f.poll())
    }

    pub fn poll_fn_notify(&mut self,
                             notify: &N,
                             id: usize,
                             f: F) -> R
        where F: FnOnce(&mut T) -> R,
              N: Clone + Into,
    {
        let mk = || notify.clone().into();
        self.enter(BorrowedUnpark::new(&mk, id), f)
    }

    fn enter(&mut self, unpark: BorrowedUnpark, f: F) -> R
        where F: FnOnce(&mut T) -> R
    {
        let borrowed = BorrowedTask {
            id: self.id,
            unpark: unpark,
            events: BorrowedEvents::new(),
            map: &self.data,
        };
        let obj = &mut self.obj;
        set(&borrowed, || f(obj))
    }

pub fn set<'a, F, R>(task: &BorrowedTask<'a>, f: F) -> R
    where F: FnOnce() -> R
{
    // Lazily initialize the get / set ptrs
    //
    // Note that we won't actually use these functions ever, we'll instead be
    // testing the pointer's value elsewhere and calling our own functions.
    INIT.call_once(|| unsafe {
        let get = mem::transmute::(0x1);
        let set = mem::transmute::(0x2);
        init(get, set);
    });

    // Same as above.
    if core::is_get_ptr(0x1) {
        struct Reset(*const Cell<*mut u8>, *mut u8);

        impl Drop for Reset {
            #[inline]
            fn drop(&mut self) {
                unsafe {
                    (*self.0).set(self.1);
                }
            }
        }

        unsafe {
            let slot = tls_slot();
            let _reset = Reset(slot, (*slot).get());
            (*slot).set(task as *const _ as *mut u8);
            f()
        }
    } else {
        core::set(task, f)
    }
}
pub fn set<'a, F, R>(task: &BorrowedTask<'a>, f: F) -> R
    where F: FnOnce() -> R
{
    let set = match SET.load(Relaxed) {
        0 => panic!("not initialized"),
        n => unsafe { mem::transmute::(n) },
    };

    struct Reset(fn(*mut u8), *mut u8);

    impl Drop for Reset {
        #[inline]
        fn drop(&mut self) {
            (self.0)(self.1);
        }
    }

    let _reset = Reset(set, get_ptr().unwrap());
    set(task as *const _ as *mut u8);
    f()
}

从这已经可以看到,就是由futures的executor来poll传入的future,而这个future来做shutdown的清理工作

你可能感兴趣的:(结合源码理解tokio)