gpt4 book ai didi

c++ - 使用 Boost.Lockfree 队列比使用互斥锁慢

转载 作者:IT老高 更新时间:2023-10-28 12:28:57 27 4
gpt4 key购买 nike

直到现在我还在我的项目中使用 std::queue。我测量了此队列上的特定操作所需的平均时间。

时间是在 2 台机器上测量的:我的本地 Ubuntu 虚拟机和远程服务器。使用 std::queue,两台机器上的平均值几乎相同:约 750 微秒。

然后我将std::queue“升级”为boost::lockfree::spsc_queue,这样我就可以摆脱保护队列的互斥锁。在我的本地 VM 上,我可以看到巨大的性能 boost ,现在平均为 200 微秒。然而,在远程机器上,平均时间达到了 800 微秒,这比以前慢了。

首先我认为这可能是因为远程机器可能不支持无锁实现:

来自 Boost.Lockfree page:

Not all hardware supports the same set of atomic instructions. If it is not available in hardware, it can be emulated in software using guards. However this has the obvious drawback of losing the lock-free property.

为了确定是否支持这些指令,boost::lockfree::queue 有一个名为 bool is_lock_free(void) const; 的方法。但是,boost::lockfree::spsc_queue 没有这样的功能,对我来说,这意味着它不依赖于硬件并且始终是无锁的——在任何机器上。

性能下降的原因可能是什么?


示例代码(生产者/消费者)

// c++11 compiler and boost library required

#include <iostream>
#include <cstdlib>
#include <chrono>
#include <async>
#include <thread>
/* Using blocking queue:
* #include <mutex>
* #include <queue>
*/
#include <boost/lockfree/spsc_queue.hpp>


boost::lockfree::spsc_queue<int, boost::lockfree::capacity<1024>> queue;

/* Using blocking queue:
* std::queue<int> queue;
* std::mutex mutex;
*/

int main()
{
auto producer = std::async(std::launch::async, [queue /*,mutex*/]()
{
// Producing data in a random interval
while(true)
{
/* Using the blocking queue, the mutex must be locked here.
* mutex.lock();
*/

// Push random int (0-9999)
queue.push(std::rand() % 10000);

/* Using the blocking queue, the mutex must be unlocked here.
* mutex.unlock();
*/

// Sleep for random duration (0-999 microseconds)
std::this_thread::sleep_for(std::chrono::microseconds(rand() % 1000));
}
}

auto consumer = std::async(std::launch::async, [queue /*,mutex*/]()
{
// Example operation on the queue.
// Checks if 1234 was generated by the producer, returns if found.

while(true)
{
/* Using the blocking queue, the mutex must be locked here.
* mutex.lock();
*/

int value;
while(queue.pop(value)
{
if(value == 1234)
return;
}

/* Using the blocking queue, the mutex must be unlocked here.
* mutex.unlock();
*/

// Sleep for 100 microseconds
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}

consumer.get();
std::cout << "1234 was generated!" << std::endl;
return 0;
}

最佳答案

无锁算法通常比基于锁的算法性能更差。这是它们几乎没有被频繁使用的一个关键原因。

无锁算法的问题在于,它们通过允许竞争线程继续竞争来最大化竞争。锁通过取消调度竞争线程来避免争用。无锁算法,第一个近似值,只应在无法取消调度竞争线程时使用。这很少适用于应用程序级代码。

让我给你一个非常极端的假设。想象一下,四个线程在一个典型的现代双核 CPU 上运行。线程 A1 和 A2 正在操作集合 A。线程 B1 和 B2 正在操作集合 B。

首先,让我们假设集合使用锁。这意味着如果线程 A1 和 A2(或 B1 和 B2)尝试同时运行,其中一个将被锁阻塞。因此,很快,一个 A 线程和一个 B 线程将运行。这些线程将运行得非常快并且不会争用。任何时候线程试图竞争,冲突的线程都会被取消调度。耶。

现在,假设集合不使用锁。现在,线程 A1 和 A2 可以同时运行。这将导致不断的争用。集合的缓存线将在两个核心之间进行乒乓球运动。内核间总线可能会饱和。性能会很糟糕。

再一次,这被夸大了。但你明白了。您想避免争用,而不是尽可能多地忍受争吵。

但是,现在再次运行这个思想实验,其中 A1 和 A2 是整个系统上唯一的线程。现在,无锁集合可能会更好(尽管您可能会发现在这种情况下最好只有一个线程!)。

几乎每个程序员都经历过一个阶段,他们认为锁是不好的,避免锁可以让代码运行得更快。最终,他们意识到是 争用 让事情变慢并且锁定,正确使用,最大限度地减少争用。

关于c++ - 使用 Boost.Lockfree 队列比使用互斥锁慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43540943/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com