65.9K
CodeProject 正在变化。 阅读更多。
Home

单线程与双线程

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.90/5 (39投票s)

2004年10月9日

2分钟阅读

viewsIcon

105522

downloadIcon

357

对英特尔双至强 HT 技术的一种优化方法的介绍。

Sample Image - PI/PI.jpg

目录

目标

我发布这篇文章的目的是分享一些简单的优化方法。就这样!

介绍

本文演示了双线程如何比单线程表现更好,尤其是在具有 HT 技术的英特尔双至强处理器中。我在这里发布的演示是一个简单的 PI 计算,作为计算密集型函数的示例。两个 PI 函数都将以 100% 的 CPU 利用率运行。

要求

很简单。为了看到显著的改进,您需要在双 CPU 机器上进行练习。

代码

演示代码非常简单。这是一个示例的开始..

SingleThreadPIDualThreadPI 将做完全相同的事情,相同的结果,但不同的时间。主要区别在于 DualThreadPI 函数是使用数据并行化方法编写的。

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <time.h> 

#define NUM_THREADS 2 
 
HANDLE thread_handles[NUM_THREADS];
CRITICAL_SECTION hUpdateMutex;
static long num_steps = 100000 * 1000;
double step;
double global_sum = 0.0; 
 
int SingleThreadPI();
int DualThreadPI();
void ThreadPI(void *arg); 
 
int main(int argc, char* argv[])
{
  // Single Thread
  SingleThreadPI(); 
 
  // Dual Thread
  DualThreadPI(); 
 
  getchar(); 
  return 0;
} 
 
int SingleThreadPI()
{
  int start, end, total;
  start = clock(); 
  int i;
  double x, pi, sum = 0.0;
  step = 1.0/(double) num_steps;
 
  for (i=1;i<= num_steps; i++)
  {
    x = (i-0.5)*step;
    sum = sum + 4.0/(1.0+x*x);
  } 
 
  pi = step * sum;
  printf("\nSingleThreadPI\n");
  printf(" pi is %f \n",pi); 
  end = clock();
  total = end - start;
  printf("%d\n", total); 
 
  return 0;
} 
 
int DualThreadPI()
{
  int start, end, total;
  start = clock(); 
  double pi;
  int i;
  unsigned long threadID;
  int threadArg[NUM_THREADS]; 
 
  for(i=0; i<NUM_THREADS; i++)
    threadArg[i] = i+1; 
 
  InitializeCriticalSection(&hUpdateMutex); 
 
  for (i=0; i<NUM_THREADS; i++)
  {
    thread_handles[i] = CreateThread(0, 0, 
        (LPTHREAD_START_ROUTINE) ThreadPI, &threadArg[i], 0, &threadID);
  } 
 
  // wait until both threads end its processing
  WaitForMultipleObjects(NUM_THREADS, thread_handles, TRUE,INFINITE); 
 
  pi = global_sum * step;
  printf("\nDualThreadPI\n");
  printf(" pi is %f \n",pi); 
  end = clock();
  total = end - start;
  printf("%d\n", total); 
 
  return 0;
} 
 
void ThreadPI(void *arg)
{
  int i, start;
  double x, sum = 0.0; 
  start = *(int *) arg; // arg is actually the thread ID, i in the loop.
  step = 1.0/(double) num_steps; 
 
  // NUM_THREADS in this case is 2
  // so that thread ID=1, ThreadPI will compute odd number in the loop
  //         thread ID=2, ThreadPI will compute even number in the loop
  for (i=start;i<= num_steps; i=i+NUM_THREADS)
  {
    x = (i-0.5)*step;
    sum = sum + 4.0/(1.0+x*x);
  } 
 
  // try to make atomic statement, otherwise...
  EnterCriticalSection(&hUpdateMutex);
  global_sum += sum;
  LeaveCriticalSection(&hUpdateMutex);
}

测试性能

根据性能分析,正如预期的那样,这种类型的优化在单处理器机器上运行不会有显著的改进。除非在双处理器机器上运行,否则您肯定会看到单线程和双线程之间的巨大差异。 这是一个实时示例...

Machine -> Pentium 4 (2.4GHz, 1GB Memory)

Profile: Function timing, sorted by time
Date:    Sun Oct 10 02:23:09 2004 

Program Statistics
------------------
    Command line at 2004 Oct 10 02:23: "G:\j2\net\code project\article - 
         Optimise For Intel HT Technology\InLocal\PI\Release\PI" 
    Total time: 5342.205 millisecond
    Time outside of functions: 38.445 millisecond
    Call depth: 2
    Total functions: 8
    Total hits: 3
    Function coverage: 37.5%
    Overhead Calculated 4
    Overhead Average 4 
Module Statistics for pi.exe
----------------------------
    Time in module: 5303.760 millisecond
    Percent of time in module: 100.0%
    Functions in module: 8
    Hits in module: 3
    Module function coverage: 37.5% 
        Func          Func+Child           Hit
        Time   %         Time      %      Count  Function
---------------------------------------------------------
    2246.857  42.4     5303.760 100.0        1 _main (pi.obj)
    1620.240  30.5     1620.240  30.5        1 SingleThreadPI(void) (pi.obj)
    1436.662  27.1     1436.662  27.1        1 DualThreadPI(void) (pi.obj) 


Contributed by Nigel
Machine -> Dell Precision 530, Pentium Xeon (2 x 2.0GHz, 512MB Memory)

Profile: Function timing, sorted by time
Date: Sat Oct 09 16:58:43 2004


Program Statistics
------------------
Command line at 2004 Oct 09 16:58: "D:\somewhere\PI_demo\PI\Debug\PI" 
Total time: 10076.987 millisecond
Time outside of functions: 11.837 millisecond
Call depth: 2
Total functions: 7
Total hits: 3
Function coverage: 42.9%
Overhead Calculated 976
Overhead Average 976

Module Statistics for pi.exe
----------------------------
Time in module: 10065.150 millisecond
Percent of time in module: 100.0%
Functions in module: 7
Hits in module: 3
Module function coverage: 42.9%

Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
7175.142 71.3 10065.150 100.0 1 _main (pi.obj)
1931.827 19.2 1931.827 19.2 1 SingleThreadPI(void) (pi.obj)
958.182 9.5 958.182 9.5 1 DualThreadPI(void) (pi.obj)

Machine -> Pentium Xeon (2 x 2.8GHz, 512MB Memory)

(Pending...ToBeContinued...)
This one will have significant improvement. Anyone could volunteer? 

最后

实际上我已经在我办公室看到了它的性能(双至强 2.8GHz,性能翻倍),只是现在我在家,我只能提供我电脑的性能(有一点改进),剩下的就让你们自己去证明了... *wink*

学习是乐趣 =)

建议/提示

阅读完本文后,您可能想在您的应用程序中尝试一下。假设您投入了大量的努力,在实施后,结果您没有得到您期望的结果。请不要冲我来。您可能在应用程序中找错了目标。 此外,也许,您已经在单 CPU 机器上测试了您的应用程序,您不会得到太大的改进。见“要求”。本文只会为您展示隧道中的一些光明,它不会让您走得很远。这里有一些提示给您。 为了利用这种类型的优化,我的做法是对我的应用程序进行性能分析,然后针对常用函数,尤其是计算密集型函数,如压缩、图像过滤过程和其他形态学过程等。

在大型服务器应用程序中,其硬件可能每台机器至少有 2-4 个 CPU,但我以前从未尝试过。 很可能我短期内也不会尝试,因为我不从事那个领域。 但您可能想尝试一下! 如果结果不错,请不要介意在这里分享经验.. 祝你好运!

链接

英特尔网站

© . All rights reserved.