同步 异步(转)

原文链接:http://www.cnblogs.com/zhihaowang/archive/2009/07/12/10128749.html
我认为大家将异步的概念 和多线程混淆在一起了

举个简单的例子, 假设我要做 烧开水,举杠铃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个线程的情况 就留给你们自己完成了。

本人水平有限, 有错误请指出


网友回复:果然水平有限...
网友回复:刚开始看win32 位多线编程的菜鸟更应该懂得尊重。
网友回复:引用 2 楼 im2web 的回复:
刚开始看win32 位多线编程的菜鸟更应该懂得尊重。


说的是事实,一个人的水平有限,这个没涉及到尊重不尊重的问题.事实你是很有限的嘛.看你上面的文笔,都有一种直接的感觉,在复杂化一个问题.我很尊重别 人的.尤其是热衷于技术前线的人.也许并非是你的技术不行,或许是文笔不是很厉害.再或者就是我小菜鸟看问题不全面,总之没涉及不尊重你的意思.你心眼真 小,怎么就理解成那样了呢?
网友回复:up,楼主能写出来就很不错了,技术也就是这样提升的..
虽然我对多线程的内部机制不是很清楚,不过,看了 < <Windows核心编程>>里介绍的,觉得楼主说错了,多线程并不能缩短完成上述任务的时间,相反,线程间的切换要花时间,所以时间反而还会耗费更多..
我对这方面的概念也很模糊,明白的朋友请补充和更正。
网友回复:水平不行, 你应该指出错误的地方,帮助我提高。而不是在这里发出这样的论调。


线程切换是要时间的, 我介绍的是主要的实质内容。

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

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

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

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

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


个人认为epoll iocp 的出现,其实就是 对多线程 同步做法的改进, 改成了多线程 异步提醒。
因为网络的速度比cpu慢很多,多线程 同步 cpu 空等太多了。(一家之言)
网友回复:引用 3 楼 antss 的回复:
引用 2 楼 im2web 的回复:
刚开始看win32 位多线编程的菜鸟更应该懂得尊重。


说的是事实,一个人的水平有限,这个没涉及到尊重不尊重的问题.事实你是很有限的嘛.看你上面的文笔,都有一种直接的感觉,在复杂化一个问题.我很尊重别 人的.尤其是热衷于技术前线的人.也许并非是你的技术不行,或许是文笔不是很厉害.再或者就是我小菜鸟看问题不全面,总之没涉及不尊重你的意思.你心眼真 小,怎么就理解成那样了呢?



up!的确有些地方有毛病,要么就是出书的人出错了.要不就是出版社的人加了自己的色彩.
网友回复:引用 4 楼 lizhigang34 的回复:
up,楼主能写出来就很不错了,技术也就是这样提升的..
虽然我对多线程的内部机制不是很清楚,不过,看了 < <Windows核心编程>>里介绍的,觉得楼主说错了,多线程并不能缩短完成上述任务的时间,相反,线程间的切换要花时间,所以时间反而还会耗费更多..
我对这方面的概念也很模糊,明白的朋友请补充和更正。


你说的太对了.就说他把问题复杂化了嘛.还是喜欢INTEL那简单的说明文档.睡觉去了.
网友回复:引用 5 楼 im2web 的回复:
水平不行, 你应该指出错误的地方,帮助我提高。而不是在这里发出这样的论调。


线程切换是要时间的, 我介绍的是主要的实质内容。

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

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

如果线…

前面说的用线程提高效率都是在单CPU下..在一个时刻,只能有一个任务停留在CPU内,也就是说要完成"烧开水,举杠铃100下, 洗衣服"这三件事的时间应该等于各事件的时间和 切换线程的时间..因为他们是并发执行的(两个或多个事件在同一时间间隔内发生)..建议楼主看看 < <windows核心编程>>这本书里第四章在讲进程时,提到线程的概念:操作系统会为每个线程安排一定的CPU时间,它通过以一种循 环的方式为线程提供时间片,造成一种假象,仿佛所有的线程都是同时运行一样..
在多CPU下,OS会按照某种算法,让多线程真正的成为同时运行..
前两天论坛有人在讨论这个问题,你找找,看看大牛们是怎么说的, 我也学的很肤浅。

网友回复:三件事的时间应该等于各事件的时间和 切换线程的时间..因为他们是并发执行的(两个或多个事件在同一时间间隔内发生)

没错,但是关键是在io 的时候,让出cpu.而且切换的时间代价和 io等待时间比较微不足道。


如果还是坚持你的想法 ok, 我们简单的讨论一个例子,同时起2个线程 1个线程 sleep 10秒 1个线程 sleep 5秒。
按照你的想法是多少时间?

线程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;
}
网友回复:可能是我错了吧,但不知你上面的代码要不要考虑线程同步的问题??
网友回复:引用楼主 im2web 的帖子:
多线程的好处,比较容易的实现了 异步切换的思想, 因为异步的程序很难写的。多线程本身程还是以同步完成,但是应该说
比效率是比不上异步的。 而且多线很容易写, 相对效率也高。

分析的挺透彻的。
补充一点:多核下的速度提升倍数要小于核的数量,因为会访问一些共享资源,或者有IO操作,cache共享等。
网友回复:#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 ;
}
}

这个代码 在多核 和单核上面的效果是不一样的。
仔细分析 就知道 多核 的多 多在那里了

而上面的代码 多核和单核则基本没差距。

转载于:https://www.cnblogs.com/zhihaowang/archive/2009/07/12/10128749.html

展开阅读全文
博主设置当前文章不允许评论。

异步同步问题

06-18

大家好,rn 我们在wp8开发过程中遇到异步转同步问题如下:rn rn1.在C++组件中希望通过委托来调用C#层的函数实现,但是C#层的函数使用了大量的异步操作(async,await关键字),而需要设置到C++组件的委托函数不能是异步操作,所以需要将异步转同步处理,使用如下函数处理:rnrn /// rn /// 异步转同步rn /// rn /// rn public static void AsyncRun(Func func)rn rn //func为空 不执行rn if (func == null)rn rn return;rn rn Task.Run(async () =>rn rn await func.Invoke();rn ).Wait();rn rn2.由于AsyncRun方法在非UI线程中处理,如果func方法中有对UI的操作,则程序奔溃。那么又需要通过System.Windows.Deployment.Current.Dispatcher.BeginInvoke将func方法强制设置到UI线程中处理,使用如下函数处理: rnrn /// rn /// 异步转同步rn /// rn /// rn public static void AsyncRun(Func func)rn rn //func为空 不执行rn if (func == null)rn rn return;rn rn Task.Run(async () =>rn rn System.Windows.Deployment.Current.Dispatcher.BeginInvoke(async () =>rn rn if (func != null)rn rn await func.Invoke();rn rn );rn ).Wait();rn rnrn3.但是BeginInvoke执行的是异步处理,这样处理下来,又无法达到同步处理的效果,后续又做了如下改动rn /// rn /// 异步转同步rn /// rn /// rn public static void AsyncRun(Func func)rn rn //func为空 不执行rn if (func == null)rn rn return;rn rnrn EventWaitHandle Wait = new AutoResetEvent(false);rn System.Windows.Deployment.Current.Dispatcher.BeginInvoke(async () =>rn rn tryrn rn await func.Invoke();rn rn catch (System.Exception ex)rn rnrn rn Wait.Set();rn );rn // wait while func.Invoke() on UIrn Wait.WaitOne();rn rnrn在非UI线程下,运行是正常的,但在UI线程,AsyncRun方法会出现死循环(因为EventWaitHandle阻塞了UI线程)。rn rn在实际项目中,遇到情况比较复杂,可能是UI线程操作,也可能是非UI。目前不知道在UI线程下,怎么实现同步操作。rn rn附示例代码rnhttps://skydrive.live.com/redir?resid=82F5E40F919E82BF!144&authkey=!AJ1OGBJKQewVvNkrnrn附件为简单的实例代码,请问,怎么实现UI线程下的同步操作呢?或者有什么好的处理方案吗?rn rn谢谢。 论坛

没有更多推荐了,返回首页