我认为大家将异步的概念 和多线程混淆在一起了举个简单的例子, 假设我要做 烧开水,举杠铃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个线程的情况 就留给你们自己完成了。本人水平有限, 有错误请指出
举杠铃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个线程的情况 就留给你们自己完成了。本人水平有限, 有错误请指出
虽然我对多线程的内部机制不是很清楚,不过,看了<<Windows核心编程>>里介绍的,觉得楼主说错了,多线程并不能缩短完成上述任务的时间,相反,线程间的切换要花时间,所以时间反而还会耗费更多..
我对这方面的概念也很模糊,明白的朋友请补充和更正。
如果是单线同步,效率就会低很多。单核心下 多线程提高的地方,大多数情况下 我认为可以简单的认为就是io的时候,cpu 切到另一个线程,提高了效率。 而切换的代价忽略不计。如果线程本身很多,那么它切换的代价就很大。这个和操作系统的进程切换是一个概念。线程切换的 原理和 os 的进程切换 我感觉很相似。os 的进程切换也有代价, 操作系统
里面也学过了,如果全是cpu 计算,分时操作系统不能提高速度,只会降低速度.多线程也一样。以网络操作为例
如果用全异步做,速度无疑更快。 这点上 steven 在他的upn 里面已经证明了
但是他同时也说考虑到异步代码的复杂和难写,多线程是很好的选择。
个人认为epoll iocp 的出现,其实就是 对多线程+ 同步做法的改进, 改成了多线程 +异步提醒。
因为网络的速度比cpu慢很多,多线程+ 同步 cpu 空等太多了。(一家之言)
你说的太对了.就说他把问题复杂化了嘛.还是喜欢INTEL那简单的说明文档.睡觉去了.
在多CPU下,OS会按照某种算法,让多线程真正的成为同时运行..
前两天论坛有人在讨论这个问题,你找找,看看大牛们是怎么说的, 我也学的很肤浅。
按照你的想法是多少时间? 线程A 需要运行的时间 10秒
线程B 需要运行的时间 5秒单核cpu 上面, 2个线程是需要 15秒?还是10秒结束?
下面是代码 跑了以后 然后再来看我的帖子。#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;
}
补充一点:多核下的速度提升倍数要小于核的数量,因为会访问一些共享资源,或者有IO操作,cache共享等。
#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++;
}
}这个代码 在多核 和单核上面的效果是不一样的。
仔细分析 就知道 多核 的多 多在那里了而上面的代码 多核和单核则基本没差距。