【问题标题】:Does this multithreaded program perform better than the non-multithreaded one?这个多线程程序是否比非多线程程序执行得更好?
【发布时间】:2009-05-17 20:37:03
【问题描述】:

我的一位同事让我为他写作业。虽然这样做不太合乎道德,但我还是认罪了。 问题是这样的: 用 C 编写一个程序,计算序列 12 + 22 + ... + n2。 假设 n 是 p 的倍数,p 是线程数。 这是我写的:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define SQR(X) ((X) * (X))

int n, p = 10, total_sum = 0;

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
/* Function prototype */
void *do_calc(void *arg);

int main(int argc, char** argv)
{
    int i;
    pthread_t *thread_array;
    printf("Type number n: ");
    fscanf(stdin, "%d", &n);

    if (n % p != 0 ) {
        fprintf(stderr, "Number must be multiple of 10 (number of threads)\n");
        exit(-1);
    }


    thread_array = (pthread_t *) malloc(p * sizeof(pthread_t));
    for (i = 0; i < p; i++)
        pthread_create(&thread_array[i], NULL, do_calc, (void *) i);
    for (i = 0; i < p; i++)
        pthread_join(thread_array[i], NULL);

    printf("Total sum: %d\n", total_sum);
    pthread_exit(NULL);
}

void *do_calc(void *arg)
{
    int i, local_sum = 0;
    int thr = (int) arg;
    pthread_mutex_lock(&mtx);
    for (i = thr * (n / p); i < ((thr + 1) * (n / p)); i++)
    local_sum += SQR(i + 1);
    total_sum += local_sum;
    pthread_mutex_unlock(&mtx);
    pthread_exit(NULL);
}

除了逻辑/句法的观点,我想知道:

  1. 各个非多线程程序将如何执行
  2. 我如何测试/查看它们的性能
  3. 不使用线程的程序会是什么

提前致谢,我期待阅读您的想法

【问题讨论】:

    标签: c multithreading unix


    【解决方案1】:

    您在计算之前获取互斥锁。您应该在对局部值求和之前立即执行此操作。

    pthread_mutex_lock(&mtx);
    total_sum += local_sum;
    pthread_mutex_unlock(&mtx);
    

    【讨论】:

    【解决方案2】:

    这取决于你有多少 CPU。使用单个 CPU 内核,计算密集型程序永远不会在多线程下运行得更快。

    此外,由于您是在持有锁的情况下完成所有工作,因此您最终只会在任何时候运行一个线程,因此它实际上是单线程的。

    【讨论】:

    • 你的打印速度比我快=(我同意。
    • 55% 被接受的答案是这个,另外 45% 是 ebo 的。 :)
    【解决方案3】:

    不要打扰线程等。事实上,根本不要在循环中做任何添加。只需使用这个公式:

    ∑(r = 1; n) r^2 = 1/6 * n (n + 1)(2 n + 1) [1]

    [1]http://thesaurus.maths.org/mmkb/entry.html?action=entryById&id=1539

    【讨论】:

      【解决方案4】:

      由于您的代码在实际计算中是由互斥体序列化的,因此它会比非线程版本慢。当然,您可以轻松地自己测试一下。

      【讨论】:

      • 怎么样?这是我的问题之一。
      • 创建一个没有所有线程代码的版本并比较性能。
      【解决方案5】:

      我会尝试看看这些计算需要多少。如果它只是一小部分时间,那么我可能会选择单个进程模型,因为为每个计算生成一个线程本身会产生一些开销。

      【讨论】:

        【解决方案6】:

        要比较性能,只需记住程序启动时的系统时间,从 n=1000 调用它,然后在结束时查看系统时间。与非线程程序结果进行比较。 正如 bdonlan 所说,非线程会运行得更快

        【讨论】:

        • 1000 将远低于获得任何合理的结果,即使程序是正确的。
        • 哦不,n=1000 会溢出整数... n=50
        • 这可能是另一个问题。我正在考虑性能观点。
        • 是的,低 n 带来较差的统计数据,但高 n ovrflows 整数。最好使用至少长类型并找到最大的工作'n'并运行测试〜100次。我不确定缓存,它可能会污染结果 =(
        【解决方案7】:

        1) 单线程的性能可能会比这好一点,因为所有的计算都是在一个锁内完成的,而且锁的开销会增加总时间。最好只在将局部和添加到总和时锁定,或者将局部和存储在数组中并在主线程中计算总和。

        2) 在代码中使用时序语句来测量算法期间经过的时间。在多线程情况下,只测量主线程上的经过时间。

        3) 源自您的代码:

        int i, total_sum = 0;
        for (i = 0; i < n; i++)
          total_sum += SQR(i + 1);
        

        【讨论】:

        • 3 是个坏主意,因为所有线程都在不断地写入共享值。一旦计算了 Local_sum,最好只在线程结束时写入一次。
        • 稍微详细地说,每次处理器写入变量时,所有其他处理器都必须从本地缓存中删除该变量并稍后重新读取。这是非常非常昂贵的
        • @Tom: 3 回答了第三个问题:不使用线程的程序是什么。多线程在 3 中不是问题。
        【解决方案8】:

        一个更大的考虑因素是调度。实现内核端线程的最简单方法是让每个线程都获得相同的时间。进程只是拥有自己内存空间的线程。如果所有线程的时间相等,则添加一个线程会将您从 1/n 的时间缩短到 2/(n + 1) 的时间,这显然更好,因为 > 0 个不是您的其他线程。

        不过,实际的实现可能而且确实有很大差异。

        【讨论】:

          【解决方案9】:

          有点离题,但也许可以通过让每个线程将其结果写入数组元素来避免互斥锁(因此分配“results = calloc(sizeof(int), p)”(顺便说一句,“p”是一个糟糕的名字对于保存线程数的变量)和结果[thr] = local_sum),并让加入线程(嗯,main())对结果进行求和。所以每个线程只负责计算它的总数:只有 main() 协调线程,将它们的数据连接在一起。关注点分离。

          对于额外的功劳 (:p),使用传递给 do_calc() 的 arg 作为传递线程 ID 和写入结果的位置的一种方式,而不是依赖于全局数组。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-11-25
            • 2013-11-25
            • 1970-01-01
            • 2012-07-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多