5

Fiber-compatible Future

 3 years ago
source link: https://blog.the-pans.com/fiber-compatible-future/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Article folly

Fiber-compatible Future

Lu Pan

19 Oct 2021 • 1 min read
Fiber-compatible Future

folly's Future API is Fiber-compatible.

Calling get() on a folly::Future object will only suspend the calling fiber-task. It won't block the system thread, letting it process other tasks. – https://github.com/facebook/folly/blob/master/folly/fibers/README.md

But how does it actually work? E.g. what happens when calling folly::futures::sleep(1).get() inside a Fiber?

When you call get() on a future, it will first wait() https://github.com/facebook/folly/blob/master/folly/futures/Future-inl.h#L2259-L2265 until the promise is fulfilled.

template <class T>
Try<T> SemiFuture<T>::getTry() && {
  wait();
  auto future = folly::Future<T>(this->core_);
  this->core_ = nullptr;
  return std::move(std::move(future).result());
}
1234567

wait() is implemented by waiting on a baton of FutureBatonType which is typedefed to folly::fibers::Baton (https://github.com/facebook/folly/blob/master/folly/futures/Future-inl.h#L2078-L2099).

template <class FutureType, typename T = typename FutureType::value_type>
void waitImpl(FutureType& f) {
  if (std::is_base_of<Future<T>, FutureType>::value) {
    f = std::move(f).via(&InlineExecutor::instance());
  }
  // short-circuit if there's nothing to do
  if (f.isReady()) {
    return;
  }

  Promise<T> promise;
  auto ret = convertFuture(promise.getSemiFuture(), f);
  FutureBatonType baton;
  f.setCallback_([&baton, promise = std::move(promise)](
                     Executor::KeepAlive<>&&, Try<T>&& t) mutable {
    promise.setTry(std::move(t));
    baton.post();
  });
  f = std::move(ret);
  baton.wait();
  assert(f.isReady());
}
12345678910111213141516171819202122

This code says

  • if f is a child of Future<T> type, just execute the future inline
  • it schedules a callback on the future, which posts the baton when ready
  • it then waits on the baton

Now it's clear that why folly::Future is fiber-compatible. The short answer is that because it uses fiber::baton for waiting. When a fiber::baton is waited upon, it will try to get the thread-local fiber manager FiberManager::getFiberManagerUnsafe() if it has one. Then it can perform cooperative multi-tasking.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK