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. 我也说说Emacs吧(2) - Emacs其实就是函数的组合

    Emacs本质上是函数的组合 从帮助上看emacs有何不同 Vim和Sublime Text等编辑器,本质上是一个编辑器. 比如我们看看vim的帮助,是这个风格的,比如我要看i命令的帮助: <i ...

  2. IOS开发 static关键字的作用

    (1)函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次, 因此其值在下次调用时仍维持上次的值: (2)在模块内的 static 全局变量可以被模块内所 ...

  3. PDF文档过期时间/自毁设置

    不是很完美的方法,可以凑活着用: 切换到Pages预览页,右击页面选页面属性 切换到Action,选Run a Javascript,代码: // PDF JavaScript to make it ...

  4. 升级到XE10

    下午抽空从XE7升级到XE10,用的是lsuper大侠的Dx10Update1_23.0.21418.4207,用到的控件基本装全乎了. 过程中也碰到点问题,记录下子. 1. cnPack结构匹配线与 ...

  5. java 实现共享锁和排它锁

    一直对多线程有恐惧,在实现共享锁和排它锁之后,感觉好了很多. 共享锁    就是查询的时候,如果没有修改,可以支持多线程查询: 排它锁    就是修改的时候,锁定共享锁,停止查询,同时,锁定排它锁,只 ...

  6. wampserver2.5的php.ini位置在wamp\bin\apache\apache2.4.9\bin

    wampserver2.5的php.ini位置在wamp\bin\apache\apache2.4.9\bin php.ini有多个地方,C:\wamp\bin\php\php5.5.12下面有php ...

  7. php序号发生器,数字重组,可以隐藏原来的1,2,3。。。

    一个晚上的成果,原理: 将1,2,3,4,5,6,7,8,9,0映射到9,5,1,0,4,8,7,3,2,6 同理映射base,base有1-10种数组,也就是可以一位数到10位数 $base 实际上 ...

  8. java基础--关键字

  9. np.random的随机数函数

    np.random的随机数函数(1) 函数 说明 rand(d0,d1,..,dn) 根据d0‐dn创建随机数数组,浮点数, [0,1),均匀分布 randn(d0,d1,..,dn) 根据d0‐dn ...

  10. Sqlite基础简介

    1.什么是SQLite ? -> SQLite简介 SQLite 是一个进程内的库,是一种轻量级的.自给自足的.无服务器的.无需配置的,事务性的SQL数据库引擎.和他其他的数据库一样,SQLit ...