我认为大家将异步的概念 和多线程混淆在一起了举个简单的例子,  假设我要做 烧开水,举杠铃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个线程的情况 就留给你们自己完成了。本人水平有限, 有错误请指出

解决方案 »

  1.   

    刚开始看win32 位多线编程的菜鸟更应该懂得尊重。
      

  2.   

    up,楼主能写出来就很不错了,技术也就是这样提升的..
    虽然我对多线程的内部机制不是很清楚,不过,看了<<Windows核心编程>>里介绍的,觉得楼主说错了,多线程并不能缩短完成上述任务的时间,相反,线程间的切换要花时间,所以时间反而还会耗费更多..
    我对这方面的概念也很模糊,明白的朋友请补充和更正。
      

  3.   

    水平不行, 你应该指出错误的地方,帮助我提高。而不是在这里发出这样的论调。线程切换是要时间的, 我介绍的是主要的实质内容。多线程本身的流程大多数是按照同步方式来完成,因为cpu可以将线程切走,可以比较好的利用cpu
    如果是单线同步,效率就会低很多。单核心下 多线程提高的地方,大多数情况下 我认为可以简单的认为就是io的时候,cpu 切到另一个线程,提高了效率。 而切换的代价忽略不计。如果线程本身很多,那么它切换的代价就很大。这个和操作系统的进程切换是一个概念。线程切换的 原理和 os 的进程切换 我感觉很相似。os 的进程切换也有代价, 操作系统
    里面也学过了,如果全是cpu 计算,分时操作系统不能提高速度,只会降低速度.多线程也一样。以网络操作为例
    如果用全异步做,速度无疑更快。 这点上 steven 在他的upn 里面已经证明了
    但是他同时也说考虑到异步代码的复杂和难写,多线程是很好的选择。
    个人认为epoll iocp 的出现,其实就是 对多线程+ 同步做法的改进, 改成了多线程 +异步提醒。
    因为网络的速度比cpu慢很多,多线程+ 同步 cpu 空等太多了。(一家之言)
      

  4.   


    你说的太对了.就说他把问题复杂化了嘛.还是喜欢INTEL那简单的说明文档.睡觉去了.
      

  5.   

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

  6.   

    三件事的时间应该等于各事件的时间和+切换线程的时间..因为他们是并发执行的(两个或多个事件在同一时间间隔内发生)没错,但是关键是在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;
    }
      

  7.   

    分析的挺透彻的。
    补充一点:多核下的速度提升倍数要小于核的数量,因为会访问一些共享资源,或者有IO操作,cache共享等。
      

  8.   

    #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++;
    }
    }这个代码 在多核 和单核上面的效果是不一样的。
    仔细分析 就知道 多核 的多 多在那里了而上面的代码 多核和单核则基本没差距。