Thread pools & Executors

Run your concurrent code in a performant way

All about thread pools #

How do I use the thread pools? #

Wangle provides two concrete thread pools (IOThreadPoolExecutor, CPUThreadPoolExecutor) as well as building them in as part of a complete async framework. Generally you might want to grab the global executor, and use it with a future, like this:

auto f = someFutureFunction().via(getCPUExecutor()).then(...)

Or maybe you need to construct a thrift/memcache client, and need an event base:

auto f = getClient(getIOExecutor()->getEventBase())->callSomeFunction(args...)
.via(getCPUExecutor())
.then([](Result r){ .... do something with result});

vs. C++11's std::launch #

The current C++11 std::launch only has two modes: async or deferred. In a production system, neither is what you want: async will launch a new thread for every launch without limit, while deferred will defer the work until it is needed lazily, but then do the work in the current thread synchronously when it is needed.

Wangle's thread pools always launch work as soon as possible, have limits to the maximum number of tasks / threads allowed, so we will never use more threads than absolutely needed. See implementation details below about each type of executor.

Why do we need yet another set of thread pools? #

Unfortunately none of the existing thread pools had every feature needed - things based on pipes are too slow. Several older ones didn't support std::function.

Why do we need several different types of thread pools? #

If you want epoll support, you need an fd - event_fd is the latest notification hotness. Unfortunately, an active fd triggers all the epoll loops it is in, leading to thundering herd - so if you want a fair queue (one queue total vs. one queue per worker thread), you need to use some kind of semaphore. Unfortunately semaphores can't be put in epoll loops, so they are incompatible with IO. Fortunately, you usually want to separate the IO and CPU bound work anyway to give stronger tail latency guarantees on IO.

IOThreadPoolExecutor #

  • Uses event_fd for notification, and waking an epoll loop.
  • There is one queue (NotificationQueue specifically) per thread/epoll.
  • If the thread is already running and not waiting on epoll, we don't make any additional syscalls to wake up the loop, just put the new task in the queue.
  • If any thread has been waiting for more than a few seconds, its stack is madvised away. Currently however tasks are scheduled round robin on the queues, so unless there is no work going on, this isn't very effective.
  • ::getEventBase() will return an EventBase you can schedule IO work on directly, chosen round-robin.
  • Since there is one queue per thread, there is hardly any contention on the queues - so a simple spinlock around an std::deque is used for the tasks. There is no max queue size.
  • By default, there is one thread per core - it usually doesn't make sense to have more IO threads than this, assuming they don't block.

CPUThreadPoolExecutor #

  • A single queue backed by folly/LifoSem and folly/MPMC queue. Since there is only a single queue, contention can be quite high, since all the worker threads and all the producer threads hit the same queue. MPMC queue excels in this situation. MPMC queue dictates a max queue size.
  • LifoSem wakes up threads in Lifo order - i.e. there are only few threads as necessary running, and we always try to reuse the same few threads for better cache locality.
  • Inactive threads have their stack madvised away. This works quite well in combination with Lifosem - it almost doesn't matter if more threads than are necessary are specified at startup.
  • stop() will finish all outstanding tasks at exit
  • Supports priorities - priorities are implemented as multiple queues - each worker thread checks the highest priority queue first. Threads themselves don't have priorities set, so a series of long running low priority tasks could still hog all the threads. (at last check pthreads thread priorities didn't work very well)

ThreadPoolExecutor #

Base class that contains the thread startup/shutdown/stats logic, since this is pretty disjoint from how tasks are actually run

Observers #

An observer interface is provided to listen for thread start/stop events. This is useful to create objects that should be one-per-thread, but also have them work correctly if threads are added/removed from the thread pool.

Stats #

PoolStats are provided to get task count, running time, waiting time, etc.

Thread pools & Executors的更多相关文章

  1. Java theory and practice: Thread pools and work queues--reference

    Why thread pools? Many server applications, such as Web servers, database servers, file servers, or ...

  2. java 多线程--- Thread Runnable Executors

    java 实现多线程的整理: Thread实现多线程的两种方式: (1)继承 Thread类,同时重载 run 方法: class PrimeThread extends Thread { long ...

  3. 小规模的流处理框架.Part 1: thread pools

    原文链接:http://ifeve.com/part-1-thread-pools/ 很不错的一篇文章

  4. Thread Pools

    许多程序会动态创建数十个设置上百个线程.举个例子,一个web服务器可能在每一个新到来的请求时创建一个新线程,然后在请求完成后将其终止. 然而,创建一个新线程将会带来一定的耗费:它需要在内核中创建自身必 ...

  5. java thread reuse(good)

    I have always read that creating threads is expensive. I also know that you cannot rerun a thread. I ...

  6. 【转】Java 并发:Executors 和线程池

    原文地址: http://baptiste-wicht.com/posts/2010/09/java-concurrency-part-7-executors-and-thread-pools.htm ...

  7. The threads in the thread pool will process the requests on the connections concurrently.

    https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Most of the executor implem ...

  8. The CLR's Thread Pool

    We were unable to locate this content in zh-cn. Here is the same content in en-us. .NET The CLR's Th ...

  9. Effective Java 73 Avoid thread groups

    Thread groups were originally envisioned as a mechanism for isolating applets for security purposes. ...

随机推荐

  1. java异步计算Future的使用(转)

    从jdk1.5开始我们可以利用Future来跟踪异步计算的结果.在此之前主线程要想获得工作线程(异步计算线程)的结果是比较麻烦的事情,需要我们进行特殊的程序结构设计,比较繁琐而且容易出错.有了Futu ...

  2. js 预处理 与 执行 的顺序

    链接 浏览器渲染 js先编译, 后执行, 而且先在第一块代码段编译执行, 再到第二个代码段, 代码段之间是可以共享变量的 DOMContentLoaded

  3. 【PL/SQL编程】循环语句

    1. loop语句 loop plsql_sentence; exit when end_condition_exp; end loop; loop语句会先执行一次循环体,然后再判断“exit whe ...

  4. jfreechart 在jsp页面显示所画的图片(resin服务器的servelet配置是关键)(图片只过内存)

    用的web服务器是resin服务器,在配置web.xml时需要注意,其实resin服务器的web.xml服务器配置和tomcat服务器的配置很像, 1. 我第一次按照自己的想法,想当然的在resin- ...

  5. 深度学习(六十四)Faster R-CNN物体检测

  6. D3.js 使用心得

    教程 D3.js 入门教程系列 http://www.ourd3js.com/wordpress/296/ 全球地图数据

  7. 胖AP基本配置:

      配置思路: 先创建wlan并广播ssid 进入射频子接口封装用户vlan 进入射频口关联wlan 注意:03 多个无线信号配置 注:在把AP改为 ap-mode fat后不能退出特权模式,不然需要 ...

  8. 动态Json字符串的解析

    动态Json字符串的解析 对于传统的Json字符串,比如有规定属性的对象,通常都会采用反序列化的方式就可以了,例如下面的方式: DataContractJsonSerializer ser = new ...

  9. Filter学习(一)

    一.Filter简介 Filter:可以对web服务器管理的所有web资源(如Jsp, Servlet, 静态图片文件或静态 html 文件等)进行拦截,从而实现一些特殊的功能.例如实现URL级别的权 ...

  10. asp.net core microservices 架构之 分布式自动计算(一)

       一:简介   自动计算都是常驻内存的,没有人机交互.我们经常用到的就是console job和sql job了.sqljob有自己的宿主,与数据库产品有很关联,暂时不提.console job使 ...