Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:change thread sheduling method in ThreadPool class #2648

Open
wants to merge 11 commits into
base: unstable
Choose a base branch
from

Conversation

QlQlqiqi
Copy link

@QlQlqiqi QlQlqiqi commented May 12, 2024

The logic is based on function WriteThread::AwaitState in rocksdb. link

Before:

  1. All workers and main thread which pushs task in queue both are waiting the same lock. It can cause very intense competition.
  2. When a worker has finished one task, it will try to get lock again for a new task through function await. It can make the worker sleep with high probability due to intense competition. And it can cost much time to sleep and wake up.

After:

  1. This is a standard producer-consumer model. So we can use lock-free list to deal with this problem about intense competition.
  2. When a worker wake up, it will try to get tasks. And when it find there is no tasks, it will try to loop for a while to wait for new tasks. Because with high throughput the time for waiting new tasks is very short, so this loop will NOT cause serious block. In order to reduce the block time, the loop has 3 level.
    2.1. 1-level. Using spin-loop to wait.
    2.2. 2-level. Using long-time-loop to wait. The worker maybe yield the cpu when some condition is reached. And using a data to store probability of entering 2-level loop.
    2.3. 3-level. Using function await to wait for new tasks.

params

  1. the count of 1-level loop:
    default: 200. Too much number maybe cause high cpu load. Too few number maybe cause vain opration.
  2. queue_slow_size_:
    default: std::min(worker_num, 100). When the number of tasks in queue exceeds it, the main thread which call function Schedule call std::this_thread::yield().
  3. max_queue_size_:
    default: max_queue_size. When the number of tasks in queue exceeds it, the main thread which call function Schedule call std::this_thread::yield() till the number of tasks in queue is less than threshold.
  4. max_yield_usec_:
    default: 100. The max time of loop in 2-level loop.
  5. slow_yield_usec_:
    default: 3. If the time the function std::this_thread::yield() spends exceeds the threshold, the data sorce may be updated.
  6. kMaxSlowYieldsWhileSpinning:
    default: 3. If the times of reaching condition above(5), the data sorce will be updated.
  7. sampling_base:
    default: 256. It represent the provability of enter 2-level loop is not lower than 1/sampling_base.

@QlQlqiqi QlQlqiqi changed the title change thread sheduling method in ThreadPool class feat:change thread sheduling method in ThreadPool class May 12, 2024
@github-actions github-actions bot added the ✏️ Feature New feature or request label May 12, 2024
@QlQlqiqi QlQlqiqi requested a review from AlexStocks May 12, 2024 06:43
// 1. loop for short time
for (uint32_t tries = 0; tries < 200; ++tries) {
if (newest_node_.load(std::memory_order_acquire) != nullptr) {
last = newest_node_.exchange(nullptr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里先到的线程直接摘了整个链表,据为己有,在去线性消费,可能会导致延迟波动大,建议尽量将任务均匀分给线程池里的worker。毕竟Pika读写链路上都是自己的线程,和rocksdb的线程模型差异比较大(Rocksdb这块都是application线程在对每个writer并发),这一块可能得多一些考量。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我想了一下,一次只取一定数量的 task 大概有两种办法:
1、一个 worker 对应一个无锁链表,然后新的 task 就随机或者遍历地往这些链表中加;
2、依旧使用一个无锁链表,但是无锁链表的容量较低,比如为 10 个这样的,这样保证一个 worker 一次最多取 10 个。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

第二个方法直接测试就行,第一个方法见我新的分支:https://github.com/QlQlqiqi/pika/tree/change-thread-shedule-with-mutil-list

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我这里测的结果是这两个方法速度不相上下,当然如果调参合适的话应该会有较大的差距

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✏️ Feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants