您的位置:首页 > 其它

个人认为的同步 异步 多线程 单核 多核 并行的区别

2008-08-27 09:43 369 查看
论坛里面 没人关注, 放在这里。

我认为大家将异步的概念 和多线程混淆在一起了

举个简单的例子, 假设我要做 烧开水,举杠铃100下, 洗衣服 3件事情。

烧开水 这件事情, 我要做的事情为, 准备烧开水 1分钟, 等开水烧开 8 分钟 , 关掉烧水机 1分钟
举杠铃100下 我要做的事情为, 举杠铃100下 10分钟
洗衣服 我要做的事情为, 准备洗衣服 1分钟, 等开水烧开 5 分钟 , 关掉洗衣机 1分钟

单核情况下
同步的完成,我需要做的时间为 1+ 8 +1 + 10 + 1+ 5 +1 = 27 分

如果异步,就是在等的时候,我可以切换去做别的事情

准备烧开水(1) + 准备洗衣服(1) + 举50下杠铃 (5)分钟+ 关洗衣机 1分钟 + 举杠铃20下 (2)分钟+ 关烧水机 1分钟 + 举30下杠铃(3)分钟
1+1+5+1+2+1+3 =14 分钟

多核

双核 异步 并行

核1 准备烧开水 1分钟+ 举杠铃50下(5)分钟+ 等待3分钟 + 关掉烧水机 1分钟

核2 准备洗衣服 1分钟+ 举杠铃50下(5)分钟+ 关掉洗衣机 1分钟 + 等待3分钟

其实只花了 1+5+3+1 = 10分钟

其中还有双核都等待了3分钟

双核 异步 非并行

核1 举杠铃100下(10)分钟

核2 准备烧开水 1分钟+ 准备洗衣服 1分钟+ 等待5 分钟+ + 关掉烧水机 1分钟 + 等待 1 分钟 + 关掉洗衣机 1分钟

其实只花了 1+5+3+1 = 10分钟

多线程的做法
单核下

线程1 准备烧开水 1分钟, 等开水烧开 8 分钟 , 关掉烧水机 1分钟
线程2 举杠铃100下 10分钟
线程3 准备洗衣服 1分钟, 等开水烧开 5 分钟 , 关掉洗衣机 1分钟

cpu 可能这么切换 最理想的切换方式

线程1 准备烧开水1 sleep 1 sleep 5 sleep 1 sleep 2 关开水 1分钟 exit
线程2 sleep 1 sleep 1 举杠铃50 5分钟 sleep 1 举杠铃20 2分钟 sleep1 举杠铃30下 3分钟
线程3 sleep 1 准备洗衣服1 分钟 sleep 5 关洗衣机1分钟 exit

最后使用了 14分钟 和异步是一样的。
但是实际上是不一样的,因为线程不会按照我们设想的去跑, 如果线程2 举杠铃先跑,整个流程的速度就下来了。

异步和同步的区别, 在io等待的时候,同步不会切走,浪费了时间。

如果都是独占cpu 的业务, 比如举杠铃的业务, 在单核情况下 多线和单线 没有区别。

多线程的好处,比较容易的实现了 异步切换的思想, 因为异步的程序很难写的。多线程本身程还是以同步完成,但是应该说
比效率是比不上异步的。 而且多线很容易写, 相对效率也高。

多核的好处,就是可以同时做事情, 这个和单核完全不一样的。

至于多核运行 这3个线程的情况 就留给你们自己完成了。

多线程本身的流程大多数是按照同步方式来完成,因为cpu可以将线程切走,可以比较好的利用cpu
如果是单线同步,效率就会低很多。

单核心下 多线程提高的地方,大多数情况下 我认为可以简单的认为就是io的时候,cpu 切到另一个线程,提高了效率。 而切换的代价忽略不计。

如果线程本身很多,那么它切换的代价就很大。这个和操作系统的进程切换是一个概念。

线程切换的 原理和 os 的进程切换 我感觉很相似。os 的进程切换也有代价, 操作系统
里面也学过了,如果全是cpu 计算,分时操作系统不能提高速度,只会降低速度.多线程也一样。

以网络操作为例
如果用全异步做,速度无疑更快。 这点上 steven 在他的upn 里面已经证明了
但是他同时也说考虑到异步代码的复杂和难写,多线程是很好的选择。

个人认为epoll iocp 的出现,其实就是 对多线程+ 同步做法的改进, 改成了多线程 +异步提醒。
因为网络的速度比cpu慢很多,多线程+ 同步 cpu 空等太多了。(一家之言)

下面2个多线程的代码, 分别可以看作是io 操作 和重cpu 计算的例子。

它们在单核和多核 下面的显示出来的效果是不一致的,可以帮你更好的了解 什么是多核, 什么是单核

多线程的意义。

// 类似io 操作, 多线程运行, cpu 切走,可以提高运行速度。

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

//using namespace std;

DWORD WINAPI fun1(void *);
DWORD WINAPI fun2(void *);

int main()
{

fprintf(stderr, " begin %d/n", (unsigned int)time(NULL));
HANDLE h1 = CreateThread(NULL, NULL, fun1,NULL,NULL,NULL);
HANDLE h2 = CreateThread(NULL, NULL, fun2,NULL,NULL,NULL);

::WaitForSingleObject(h2, INFINITE);
::WaitForSingleObject(h1, INFINITE);
fprintf(stderr, " end %d/n", (unsigned int)time(NULL));

CloseHandle(h1);
CloseHandle(h2);
return 0;
}

DWORD WINAPI fun1(void *)
{
fprintf(stderr, " thread1 begin %d/n", (unsigned int)time(NULL));
::Sleep(1000 *10);
fprintf(stderr, " thread1 end %d/n", (unsigned int)time(NULL));
return 0;

}

DWORD WINAPI fun2(void *)
{
fprintf(stderr, " thread2 begin %d/n", (unsigned int)time(NULL));
::Sleep(1000 *5);
fprintf(stderr, " thread2 end %d/n", (unsigned int)time(NULL));
return 0;
}

////

代码 2 重cpu计算, 单核无法提高效率,多核可以提高效率

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

//using namespace std;

DWORD WINAPI fun1(void *);
DWORD WINAPI fun2(void *);

volicate float x[1000][1000] = {0};
float y[1000][1000] = {0};
float z[1000][1000] = {0};

void funtime(float *);

int main(int argc, char *argv)
{

fprintf(stderr, " funtime z %d/n", (unsigned int)time(NULL));
funtime(&(z[0][0]));
fprintf(stderr, " funtime z %d/n", (unsigned int)time(NULL));

fprintf(stderr, " begin %d/n", (unsigned int)time(NULL));
HANDLE h1 = CreateThread(NULL, NULL, fun1,NULL,NULL,NULL);
HANDLE h2 = CreateThread(NULL, NULL, fun2,NULL,NULL,NULL);

::WaitForSingleObject(h2, INFINITE);
::WaitForSingleObject(h1, INFINITE);
fprintf(stderr, " end %d/n", (unsigned int)time(NULL));

CloseHandle(h1);
CloseHandle(h2);
getchar();

return 0;
}

DWORD WINAPI fun1(void *)
{
fprintf(stderr, " thread1 begin %d/n", (unsigned int)time(NULL));
funtime(&(x[0][0]));
::Sleep(1000 *10);
fprintf(stderr, " thread1 end %d/n", (unsigned int)time(NULL));
return 0;
}

DWORD WINAPI fun2(void *)
{
fprintf(stderr, " thread2 begin %d/n", (unsigned int)time(NULL));
funtime(&(y[0][0]));
::Sleep(1000 *5);
fprintf(stderr, " thread2 end %d/n", (unsigned int)time(NULL));
return 0;
}

void funtime(float *table)
{
unsigned int t = time(NULL);
float PI = 3.14156925354;
for (int k =0; k < 100;k++)
for (int x = 0; x < 1000; ++x)
for (int y = 0; y < 1000; ++y) {
*(table +x*1000+ y) = PI *(t+x)*(t+y);
t++;
}
}




gaoteng1984

多核下的速度提升倍数要小于核的数量,因为会访问一些共享资源,或者有IO操作,cache共享等 的看法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: