首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么6-7个线程比20个线程快?

为什么6-7个线程比20个线程快?
EN

Stack Overflow用户
提问于 2015-05-01 15:24:52
回答 4查看 277关注 0票数 2

在学校,我们被介绍给C++11线程。老师给了我们一个简单的评估,那就是用20个线程制作一个基本的网络爬虫。对我来说,线程是非常新的,尽管我确实了解基本知识。

我想提一提的是,我并不是想找人来完成我的评估,因为我已经完成了。我只想了解为什么使用6个线程总是比使用20个线程快。

请参阅下面的代码示例。

main.cpp:

代码语言:javascript
运行
复制
do
{
    for (size_t i = 0; i < THREAD_COUNT; i++)
    {
        threads[i] = std::thread(SweepUrlList);
    }

    for (size_t i = 0; i < THREAD_COUNT; i++)
    {
        threads[i].join();
    }

    std::cout << std::endl;
    WriteToConsole();
    listUrl = listNewUrl;
    listNewUrl.clear();
} while (listUrl.size() != 0);

基本上,这为每个工作线程分配要完成的作业,即下面可以找到的方法SweepUrlList,然后加入所有线程。

代码语言:javascript
运行
复制
while (1)
{
    mutextGetNextUrl.lock();
    std::set<std::string>::iterator it = listUrl.begin();
    if (it == listUrl.end())
    {
        mutextGetNextUrl.unlock();
        break;
    }
    std::string url(*it);
    listUrl.erase(*it);
    mutextGetNextUrl.unlock();
    ExtractEmail(url, listEmail);
    std::cout << ".";
}

因此,每个工作线程循环,直到ListUrl为空。ExtractEmail是一种下载网页(使用curl)并解析它以从mailto链接中提取电子邮件的方法。ExtractEmail中唯一的阻塞调用如下:

代码语言:javascript
运行
复制
if(email.length() != 0)
{
    mutextInsertNewEmail.lock();
    ListEmail.insert(email);
    mutextInsertNewEmail.unlock();
}

欢迎所有答案,并在可能的情况下链接到您发现的任何文档来回答这个问题。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-05-01 15:36:00

这是线程处理的一个相当普遍的问题,其核心是:

您演示的是线程调度。操作系统将与不同的线程一起工作,并在当前无法工作的地方安排工作。

假设您有4个内核和超线程,那么您有8个处理器可以承载负载,但也可以承载其他应用程序(操作系统、C++调试器和要启动的应用程序)。

从理论上讲,在大约8个密集线程之前,您的性能可能还不错。当您到达您的处理器能够有效使用的线程最多的时候,那么线程就开始相互竞争资源。这可以通过糟糕的性能(尤其是密集的应用程序和紧密的循环)来看出。

最后,这是一个简单的答案,但我怀疑你看到了什么。

票数 3
EN

Stack Overflow用户

发布于 2015-05-01 15:36:15

简单的答案是窒息点。你正在做的事情造成了一个瓶颈。当这种情况发生时,就会放慢速度。它可能是您正在进行的活动连接的数量,或者仅仅是线程的数量和内存大小的额外开销(请参见下面关于核心是这些瓶颈之一的答案)。

您将需要设置一系列监视器,以调查您的阻塞点在哪里,以及需要更改什么才能达到规模。每个行业的许多系统每天都面临这个问题。在一端打开节流阀并不等于另一端输出的增加。在这种情况下,它可以减少另一端的输出。

举个例子,个人离开大厅。我们的目标是尽快把100人从大楼里救出来。如果单个文件产生的速率为每1秒1人,那么100秒就可以清除建筑物。我们很多人都能把一半的时间发送给他们,同时派出2人,所以50秒就可以清理大楼了。如果我们把它们并排送出去呢。这扇门只有2米宽,所以8道门的宽度相当于4米,只有50%的第一排门能通过。其他4将导致下一行的阻塞,以此类推。视速度而定,这可能会造成暂时的堵塞,使时间增加10倍。

票数 3
EN

Stack Overflow用户

发布于 2015-05-01 15:36:35

线程是一个操作系统结构。基本上,每个线程的状态(基本上是所有CPU的寄存器和作为进程构造一部分的虚拟内存映射)由操作系统保存。一旦操作系统给出了特定的线程“执行时间”,它就会恢复这个状态并让它运行。一旦这一次结束,它就必须保存这个状态。保存一个特定线程的状态并恢复另一个线程的过程称为上下文切换,它需要大量的时间(通常在几百到1000个CPU周期之间)。

对上下文切换也有额外的惩罚。一些处理器的高速缓存(如称为TLB的虚拟内存转换缓存)必须被刷新,流水线指令将被丢弃等等。通常,您希望尽可能减少上下文切换。

如果您的CPU有4个核心,则4个线程可以同时运行。如果您尝试在一个4核心系统上运行20个线程,那么操作系统必须管理这些线程之间的时间,因此看起来它们似乎是并行运行的。例如,线程1-4将运行50毫秒,然后5-9将运行50毫秒,等等。

因此,如果您的所有线程都在运行CPU密集型操作,通常最有效的方法是让您的程序使用与内核相同数量的线程(有时在windows中称为“处理器”)。如果您有更多的线程而不是内核,那么就必须进行上下文切换,并且这是可以最小化的开销。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29989768

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档