热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

提高多线程程序的速度

如何解决《提高多线程程序的速度》经验,为你挑选了1个好方法。

我有一个简单的问题:我需要创建三个线程并在每个线程中执行某个操作.第一个线程需要添加100array[0]和减去101array[1],第二线程需要添加200array[1]并减去201array[2]而最终第三线程需要添加300array[2]并减去301array[0].

以下是正确的解决方案,但运行时间非常长.如果我使用一个线程执行此任务,则运行时间将少于1秒,但是三个线程将运行时间增加到大约10秒(+ - 2秒).问题是什么?我认为有三个线程的解决方案必须更快.可能是我以错误的方式使用互斥?

#include 
#include 
#include 

enum {SIZE = 3, ITER = 1000000};
double array[SIZE] = {};
pthread_t threads[SIZE];

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *func(void *arg) {
    int n = *(int *)arg;
    int tmp = 100 * (n + 1),
        tmp2 = tmp + 1;
    for (int i = 0; i != ITER; ++i) {
        pthread_mutex_lock(&mutex);
        array[n % SIZE] += tmp;
        array[(n + 1) % SIZE] -= tmp2;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    int n[SIZE];
    for (int i = 0; i != SIZE; ++i) {
        n[i] = i;
        pthread_create(threads + i, NULL, func, n + i); 
    }

    for (int i = 0; i != SIZE; ++i) {
        pthread_join(threads[i], NULL);
    }

    for (int i = 0; i != SIZE; ++i) {
        printf("%.10g ", array[i]);
    }
    printf("\n");

    return 0;
}

Liran Funaro.. 5

虽然互斥锁带来了巨大的开销,但这并不是您放缓的原因.原因是互斥锁序列化执行.只有一个线程可以在任何时间点运行,因为只有一个线程可以保存互斥锁.所以你在实践中得到的是一个带有额外同步开销的串行执行.

您希望您的线程像这样运行(X代表一个正在运行的线程).

Thread1: |X|X|X|X|X|
Thread2: |X|X|X|X|X|
Thread3: |X|X|X|X|X|

但相反,你得到的是这样的:

Thread1: |X| | |X| | |X| | |X| | |X| | |
Thread2: | |X| | |X| | |X| | |X| | |X| |
Thread3: | | |X| | |X| | |X| | |X| | |X|

在每个时隙,只有一个线程运行.

有几种方法:

    您可以按照每个线程专门访问数组的不同索引的方式对操作进行分区.这样就可以避免使用互斥锁.但是,这需要对您的解决方案进行全面的重新设计.

    您可以使每个线程在数组的本地副本上工作,然后在单个线程上组合所有线程的结果.这样做要简单得多,因为您只需将数据复制到线程中,即可省去互斥锁.

    您可以为每个数组索引使用互斥锁,但由于高内存和时间开销,这似乎有点极端,因为冲突概率实际上非常低.

总而言之,使用选项1将产生最佳性能,但使用选项2将比串行版本产生显着的加速,而设计工作相对较少.选项3不明智.



1> Liran Funaro..:

虽然互斥锁带来了巨大的开销,但这并不是您放缓的原因.原因是互斥锁序列化执行.只有一个线程可以在任何时间点运行,因为只有一个线程可以保存互斥锁.所以你在实践中得到的是一个带有额外同步开销的串行执行.

您希望您的线程像这样运行(X代表一个正在运行的线程).

Thread1: |X|X|X|X|X|
Thread2: |X|X|X|X|X|
Thread3: |X|X|X|X|X|

但相反,你得到的是这样的:

Thread1: |X| | |X| | |X| | |X| | |X| | |
Thread2: | |X| | |X| | |X| | |X| | |X| |
Thread3: | | |X| | |X| | |X| | |X| | |X|

在每个时隙,只有一个线程运行.

有几种方法:

    您可以按照每个线程专门访问数组的不同索引的方式对操作进行分区.这样就可以避免使用互斥锁.但是,这需要对您的解决方案进行全面的重新设计.

    您可以使每个线程在数组的本地副本上工作,然后在单个线程上组合所有线程的结果.这样做要简单得多,因为您只需将数据复制到线程中,即可省去互斥锁.

    您可以为每个数组索引使用互斥锁,但由于高内存和时间开销,这似乎有点极端,因为冲突概率实际上非常低.

总而言之,使用选项1将产生最佳性能,但使用选项2将比串行版本产生显着的加速,而设计工作相对较少.选项3不明智.


推荐阅读
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • Linux线程的同步和互斥
    目录1、线程的互斥2、可重入VS线程安全3、线程的同步1、线程的互斥 ... [详细]
  • 作者一直强调的一个概念叫做oneloopperthread,撇开多线程不谈,本篇博文将学习,怎么将传统的IO复用pollepoll封装到C++类中。1.IO复用复习使用p ... [详细]
  • 不知道你是否还记得之前在进程中的信号处理时,提到过阻塞信号集与未决信号集的概念,如果你已经忘记了,请参考《阻塞信号与未决信号》一文回忆一下 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • Java编程思想一书中第21章并发中关于线程间协作的一节中有个关于汽车打蜡与抛光的小例子(原书的704页)。这个例子主要展示的是两个线程如何通过wait ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了一个线程多次调用一个函数相关的知识,希望对你有一定的参考价值。 ... [详细]
  • C语言编程gcc怎么生成静态库.a和动态库.so
    这篇文章将为大家详细讲解有关C语言编程gcc怎么生成静态库.a和动态库.so,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章 ... [详细]
  • 主要用的线程函数:1.创建线程:12intpthread_create(pthread_t*thread,constpthread_attr_ ... [详细]
author-avatar
2013丶峰峰最逆天_192
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有