当前位置: 首页 > 知识库问答 >
问题:

为什么使用全局变量会使多线程执行速度慢2倍,而在其他环境中会使多线程执行速度快2倍?

田宇
2023-03-14

下面的代码取自一个用G++编译的示例。多线程比单线程快2倍。

我在Visual Studio2019中执行它,结果恰恰相反:单线程比多线程快2倍。

#include<thread>
#include<iostream>
#include<chrono>
using namespace std;

using ll = long long;
ll odd, even;
void par(const ll ini, const ll fim)
{
    for (auto i = ini; i <= fim; i++)
        if (!(i & 1))
            even += i;
        
}

void impar(const ll ini, const ll fim)
{
    for (auto i = ini; i <= fim; i++)
        if (i & 1)
            odd += i;
}
int main()
{
    const ll start = 0;
    const ll end = 190000000;

/* SINGLE THREADED */
    auto start_single = chrono::high_resolution_clock::now();
    par(start, end);
    impar(start, end);
    auto end_single = chrono::high_resolution_clock::now();
    auto single_duration = chrono::duration_cast<chrono::microseconds>(end_single - start_single).count();
    cout << "SINGLE THREADED\nEven sum: " << even << "\nOdd sum: " << odd << "\nTime: " << single_duration << "ms\n\n\n";
/* END OF SINGLE*/

/* MULTI THREADED */
    even = odd = 0;
    auto start_multi= chrono::high_resolution_clock::now();
    thread t(par, start, end);
    thread t2(impar, start, end);
    t.join();
    t2.join();
    auto end_multi = chrono::high_resolution_clock::now();
    auto multi_duration = chrono::duration_cast<chrono::microseconds>(end_multi - start_multi).count();
    cout << "MULTI THREADED\nEven sum: " << even << "\nOdd sum: " << odd << "\nTime: " << multi_duration << "ms\n";
/*END OF MULTI*/
    cout << "\n\nIs multi faster than single? => " << boolalpha << (multi_duration < single_duration) << '\n';
}

但是,如果我对我的函数做一个小的修改,如下所示:

void par(const ll ini, const ll fim)
{
    ll temp = 0;
    for (auto i = ini; i <= fim; i++)
        if (!(i & 1))
            temp += i;
    even = temp;
}

void impar(const ll ini, const ll fim)
{
    ll temp = 0;
    for (auto i = ini; i <= fim; i++)
        if (i & 1)
            odd += i;
    odd = temp;
}

多线程的性能更好。我想知道是什么导致了这种行为(在实现方面有哪些可能的差异解释了它)。

此外,我还使用www.onlinegdb.com上的gcc进行了编译,结果与我的计算机中的Visual Studio类似。

共有1个答案

滕学义
2023-03-14

你是虚假分享的受害者。

oddeven紧挨着驻留,从两个线程访问它们会导致L3高速缓存行争用(也称为虚假共享)。

您可以通过将它们分散64个字节来修复它,以确保它们驻留在不同的缓存行中,例如,如下所示:

alignas(64) ll odd, even;

有了这个改变,我在使用2个线程时获得了很好的加速:

SINGLE THREADED
Even sum: 9025000095000000
Odd sum: 9025000000000000
Time: 825954ms


MULTI THREADED
Even sum: 9025000095000000
Odd sum: 9025000000000000
Time: 532420ms

至于G++的性能--它可能是在执行您手动为您做的优化。MSVC在优化全局变量时会更加小心。

 类似资料:
  • 我在程序(计时器类)中使用scheduleAtFixedRate方法。它每秒钟运行一次,但有时这种方法会变得非常快(每秒执行3-4次)。 然而,我在网上做了一些研究,发现了这个: 复制自android开发者页面: 对于固定速率执行,任务每次连续运行的开始时间都是计划的,而不考虑上一次运行的时间。如果延迟阻止计时器按时启动任务,则这可能会导致一系列串接运行(一个接一个地启动)。 我需要固定的计时器。

  • 问题内容: 据我了解,使用Java反射API会按顺序减慢代码执行速度。但是后来我看到它在Java Universe中的许多地方都在使用。仅举几例: 注解 春季框架(AOP) 冬眠 MyBatis 这意味着我错过了关于Java反射(又称优化技术)的一些事实。有指针吗? 问题答案: 要点: 因为他们别无选择 。 Java不是动态语言,因此这些框架提供服务的唯一途径是反思。 其次,请注意,在初始化期间,

  • 问题内容: 如何与线程共享全局变量? 我的Python代码示例是: 我不知道如何让两个线程共享一个变量。 问题答案: 您只需要在中声明为global ,这样就无需修改该函数本地的。 在中,您不需要执行任何特殊操作,只要您不尝试修改的值(这将创建一个局部变量以遮盖全局变量;请在需要时使用)>

  • 问题内容: 我一直在使用HTMLUnit。非常适合我的要求。但这似乎非常缓慢。例如:我已经使用HTMLUnit自动化了以下场景 代码: 它运作良好100%。但是需要3分41秒 我想执行缓慢的原因是要验证页面上的每个元素。 我的问题是如何减少HTMLUnit的执行时间?有什么方法可以禁用网页上的验证。 提前致谢! 问题答案: 对于当前的htmlUnit 2.13,设置选项与maxmax提供的设置略有

  • 问题内容: 现在我正在研究如何尽快从网站获取数据。为了获得更快的速度,即时通讯正在考虑使用多线程。这是我用来测试多线程和简单文章之间差异的代码。 如您所见,这是一个非常简单的代码。首先,我将模式设置为“ Simple”,然后我可以得到时间间隔: 50s (也许我的速度有点慢:()。然后我将模式设置为“ Multiple”,然后我得到了时间间隔: 35 。从我可以看到,多线程实际上可以提高速度,但是

  • 消费者是一个spring集成项目,它从消息队列中消费并执行大量处理。目前,它是单线程的,不能与生产者发送消息的速度匹配。因此队列深度不断增加 是否可以使用executor通道在多线程环境中处理此问题并加快使用者进程 如果是,请建议如何实现--为了确保消息的顺序,我需要将相同类型的消息(基于消息的id)分配给executor通道的相同线程。 因此executor通道上的BridgeTo将转发消息