单线程_单线程 多线程 - CSDN
精华内容
参与话题
  • 单线程与多线程的区别

    万次阅读 多人点赞 2018-07-02 14:05:52
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。什么是多线程?多线程是指程序中包含多个执行流,即在一个程序中可以同时运行...

    什么是进程?
    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
    而一个进程又是由多个线程所组成的。


    什么是线程?
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,
    即不同的线程可以执行同样的函数。


    什么是多线程?
    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
    也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。


    多线程的好处:
    可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,
    这样就大大提高了程序的效率。 


    多线程的不利方面:
    线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 
    多线程需要协调和管理,所以需要CPU时间跟踪线程; 
    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
    线程太多会导致控制太复杂,最终可能造成很多Bug;


    多线程与单线程的区别
    生活举例
    你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。
    如果你一手接电话,一手打卡。就是多线程。
    2件事的结果是一样的。。你接了电话且打了卡。


    多线程处理的优点

    同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。例如,文字处理器应用程序在您处理文档的同时,可以检查拼写(作为单独的任务)。由于多线程应用程序将程序划分成独立的任务,因此可以在以下方面显著提高性能: 
    多线程技术使程序的响应速度更快,因为用户界面可以在进行其他工作的同时一直处于活动状态。 
    当前没有进行处理的任务可以将处理器时间让给其他任务。 
    占用大量处理时间的任务可以定期将处理器时间让给其他任务。 
    可以随时停止任务。 
    可以分别设置各个任务的优先级以优化性能。 

    是否需要创建多线程应用程序取决于多个因素。在以下情况下,最适合采用多线程处理:
    耗时或大量占用处理器的任务阻塞用户界面操作。 
    各个任务必须等待外部资源(如远程文件或 INTERNET 连接)。 

    例如,用于跟踪 WEB 页上的链接并下载满足特定条件的文件的 INTERNET 应用程序“ROBOT”。这种应用程序可以依次同步下载各个文件,也可以使用多线程同时下载多个文件。多线程方法比同步方法的效率高很多,因为即使在某些线程中远程 WEB 服务器的响应非常慢,也可以下载文件。

    下面是多线程的例子
    还在DOS时代,人们就在寻求一种多任务的实现。于是出现了TSR类型的后台驻留程序,比较有代表性的有SIDE KICK、VSAFE等优秀的TSR程序,这类程序的出现和应用确实给用户使用计算机带来了极大的方便,比如SIDE KICK,们编程可以在不用进编辑程序的状态下,一边编辑源程序,一边编译运行,非常方便。但是,DOS单任务操作系统的致命缺陷注定了在DOS下不可能开发出真正的多任务程序。进入WINDOWS3.1时代,这种情况依然没有根本的改变,一次应用只能做一件事。比如数据库查询,除非应用编得很好,在查询期间整个系统将不响应用户的输入。
     进入了WINDOWS NT和WINDOWS 9X时代,情况就有了彻底的改观,操作系统从真正意义上实现了多任务(严格地说,WIN9X还算不上)。一个应用程序,在需要的时候可以有许多个执行线程,每个线程就是一个小的执行程序,操作系统自动使各个线程共享CPU资源,确保任一线程都不能使系统死锁。这样,在编程的时候,可以把费时间的任务移到后台,在前台用另一个线程接受用户的输入。对那些对实时性要求比较高的编程任务,如网络客户服务、串行通信等应用时,多线程的实现无疑大大地增强了程序的可用性和稳固性。

    ----------------------------------------------------------------------------------------------------------------------------------

    1。单进程单线程:一个人在一个桌子上吃菜。
    2。单进程多线程:多个人在同一个桌子上一起吃菜。
    3。多进程单线程:多个人每个人在自己的桌子上吃菜。

    多线程的问题是多个人同时吃一道菜的时候容易发生争抢,例如两个人同时夹一个菜,一个人刚伸出筷子,结果伸到的时候已经被夹走菜了。。。此时就必须等一个人夹一口之后,在还给另外一个人夹菜,也就是说资源共享就会发生冲突争抢。


    1。对于 Windows 系统来说,【开桌子】的开销很大,因此 Windows 鼓励大家在一个桌子上吃菜。因此 Windows 多线程学习重点是要大量面对资源争抢与同步方面的问题。


    2。对于 Linux 系统来说,【开桌子】的开销很小,因此 Linux 鼓励大家尽量每个人都开自己的桌子吃菜。这带来新的问题是:坐在两张不同的桌子上,说话不方便。因此,Linux 下的学习重点大家要学习进程间通讯的方法。

    --
    补充:有人对这个开桌子的开销很有兴趣。我把这个问题推广说开一下。

    开桌子的意思是指创建进程。开销这里主要指的是时间开销。
    可以做个实验:创建一个进程,在进程中往内存写若干数据,然后读出该数据,然后退出。此过程重复 1000 次,相当于创建/销毁进程 1000 次。在我机器上的测试结果是:
    UbuntuLinux:耗时 0.8 秒
    Windows7:耗时 79.8 秒
    两者开销大约相差一百倍。

    这意味着,在 Windows 中,进程创建的开销不容忽视。换句话说就是,Windows 编程中不建议你创建进程,如果你的程序架构需要大量创建进程,那么最好是切换到 Linux 系统。

    大量创建进程的典型例子有两个,一个是 gnu autotools 工具链,用于编译很多开源代码的,他们在 Windows 下编译速度会很慢,因此软件开发人员最好是避免使用 Windows。另一个是服务器,某些服务器框架依靠大量创建进程来干活,甚至是对每个用户请求就创建一个进程,这些服务器在 Windows 下运行的效率就会很差。这"可能"也是放眼全世界范围,Linux 服务器远远多于 Windows 服务器的原因。

    --
    再次补充:如果你是写服务器端应用的,其实在现在的网络服务模型下,开桌子的开销是可以忽略不计的,因为现在一般流行的是按照 CPU 核心数量开进程或者线程,开完之后在数量上一直保持,进程与线程内部使用协程或者异步通信来处理多个并发连接,因而开进程与开线程的开销可以忽略了。

    另外一种新的开销被提上日程:核心切换开销。

    现代的体系,一般 CPU 会有多个核心,而多个核心可以同时运行多个不同的线程或者进程。

    当每个 CPU 核心运行一个进程的时候,由于每个进程的资源都独立,所以 CPU 核心之间切换的时候无需考虑上下文。

    当每个 CPU 核心运行一个线程的时候,由于每个线程需要共享资源,所以这些资源必须从 CPU 的一个核心被复制到另外一个核心,才能继续运算,这占用了额外的开销。换句话说,在 CPU 为多核的情况下,多线程在性能上不如多进程。

    因而,当前面向多核的服务器端编程中,需要习惯多进程而非多线程。
    ----------------------------------------------------------------------------------------------------------------------------------

    很多人答案说的是操作系统提供的多进程而不是单个程序内的多线程。

    多线程使得程序内部可以分出多个线程来做多件事情,而不会造成程序界面卡死。比如迅雷等多线程下载工具就是典型的多线程。一个下载任务进来,迅雷把文件平分成10份,然后开10个线程分别下载。这时主界面是一个单独的线程,并不会因为下载文件而卡死。而且主线程可以控制下属线程,比如某个线程下载缓慢甚至停止,主线程可以把它强行关掉并重启另外一个线程。

    另外就是一些程序的打印功能,比如记事本、Adobe Reader,打印的时候就只能打印,无法在主界面进行操作,而Word就有“后台打印”的功能,点了打印命令之后,还可以回到主界面进行修改、保存等操作。

    另外多线程除了并行完成一些任务以外,还有生产者-消费者模式。比如Windows命令行下在某个硬盘根目录执行一个"dir/s | more"命令,前一条显示硬盘里的所有文件,要执行很久才能执行得完,后面那条命令会把前面命令的输出分屏显示出来。但是执行整条命令时,会立刻有显示,也就是说,前面一条命令输出满一页内容到缓冲区,more命令就把缓冲区封死了,等用户敲了一个键显示下一屏的时候,more命令把缓冲区的内容取出并清空,前面的命令才能输出下一屏到缓冲区。这样的多线程使得整条命令不用等待前面的命令全部执行完才能执行下一条命令。

    多线程和多进程的区别。平常指的多进程是操作系统下同时运行多个进程,比如Word和Excel同时打开,并且可以并行地同时执行一些操作。这种多进程和多线程没什么好比较的。可以比较的是同一个程序里的多线程和多进程。

    多线程因为在同一个进程里,所以可以共享内存和其他资源,比如迅雷里10个线程一齐下载一个文件,这个文件是由进程打开的,然后10个线程都可以往里写入东西。如果是10个进程就不行了,操作系统不允许一个文件由两个进程同时写入。另外,Chrome就是一个典型的多进程程序,里面每个标签页、扩展、插件都是单独的进程,各自独占资源,相互隔离,一个进程出错死掉只会影响一个页面或者插件,再也不会出现Flash插件出错崩溃导致整个浏览器崩溃的情况了。

    展开全文
  • 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。 什么是多线程? 多线程是指程序中包含多个执行流,即在一个程序中可以同时...

    什么是进程?
    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
    而一个进程又是由多个线程所组成的。

    什么是线程?
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,
    即不同的线程可以执行同样的函数。

    什么是多线程?
    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
    也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

    多线程的好处:
    可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,
    这样就大大提高了程序的效率。 

    多线程的不利方面:
    线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 
    多线程需要协调和管理,所以需要CPU时间跟踪线程; 
    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
    线程太多会导致控制太复杂,最终可能造成很多Bug;


    多线程与单线程的区别
    生活举例:
    你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。
    如果你一手接电话,一手打卡。就是多线程。
    2件事的结果是一样的。。你接了电话且打了卡。


    多线程处理的优点

    同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。例如,文字处理器应用程序在您处理文档的同时,可以检查拼写(作为单独的任务)。由于多线程应用程序将程序划分成独立的任务,因此可以在以下方面显著提高性能: 
    (1) 多线程技术使程序的响应速度更快,因为用户界面可以在进行其他工作的同时一直处于活动状态。 
    (2) 当前没有进行处理的任务可以将处理器时间让给其他任务。 
    (3) 占用大量处理时间的任务可以定期将处理器时间让给其他任务。 
    (4) 可以随时停止任务。 
    (5) 可以分别设置各个任务的优先级以优化性能。 

    是否需要创建多线程应用程序取决于多个因素。在以下情况下,最适合采用多线程处理:

    • 耗时或大量占用处理器的任务阻塞用户界面操作。 
    • 各个任务必须等待外部资源(如远程文件或 INTERNET 连接)。 

    例如,用于跟踪 WEB 页上的链接并下载满足特定条件的文件的 INTERNET 应用程序“ROBOT”。这种应用程序可以依次同步下载各个文件,也可以使用多线程同时下载多个文件。多线程方法比同步方法的效率高很多,因为即使在某些线程中远程 WEB 服务器的响应非常慢,也可以下载文件。


    下面是多线程的例子

    还在DOS时代,人们就在寻求一种多任务的实现。于是出现了TSR类型的后台驻留程序,比较有代表性的有SIDE KICK、VSAFE等优秀的TSR程序,这类程序的出现和应用确实给用户使用计算机带来了极大的方便,比如SIDE KICK,们编程可以在不用进编辑程序的状态下,一边编辑源程序,一边编译运行,非常方便。但是,DOS单任务操作系统的致命缺陷注定了在DOS下不可能开发出真正的多任务程序。进入WINDOWS3.1时代,这种情况依然没有根本的改变,一次应用只能做一件事。比如数据库查询,除非应用编得很好,在查询期间整个系统将不响应用户的输入。

     进入了WINDOWS NT和WINDOWS 9X时代,情况就有了彻底的改观,操作系统从真正意义上实现了多任务(严格地说,WIN9X还算不上)。一个应用程序,在需要的时候可以有许多个执行线程,每个线程就是一个小的执行程序,操作系统自动使各个线程共享CPU资源,确保任一线程都不能使系统死锁。这样,在编程的时候,可以把费时间的任务移到后台,在前台用另一个线程接受用户的输入。对那些对实时性要求比较高的编程任务,如网络客户服务、串行通信等应用时,多线程的实现无疑大大地增强了程序的可用性和稳固性。

    =====================================================================================

    多线程的坏处:增加了调度和管理的开销,带来了一些不确定性,需要复杂的同步机制,避免死锁等等。
    多线程的好处:一定程度上提高响应速度,在多核的情况下还是更能充分利用CPU资源的。

    =====================================================================================

    单线程就是程序执行时,所跑的程序路径(处理的东西)是连续顺序下来的,必须前面的处理好,后面的才会执行到。   
           多线程,举个例子:程序可以同时执行2个以上相同类似的操作,比如一些搜索代理或者群发email的多线程软件,由于操作一次需要网络的返回信息   花的时间比较长,而对cpu来说却是空闲的,如果是一个一个顺序执行,那么搜索几千个IP就会花上好久好久。   而如果用多线程就可以在等待期间   加入其他的搜索,然后等待,这样可以提高效率。不过多线程和多进程公用一些资源时要考虑的问题好像也是一样的,对于一些公共资源或者公共变量的访问和修改时要注意特别的,需要一些锁定什么的,还有顺序问题的考虑。  
           多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O,OEMBIOS等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。每个程序执行时都会产生一个进程,而每一个进程至少要有一个主线程。这个线程其实是进程执行的一条线索,除了主线程外你还可以给进程增加其它的线程,也即增加其它的执行线索,由此在某种程度上可以看成是给一个应用程序增加了多任务功能。当程序运行后,您可以根据各种条件挂起或运行这些线程,尤其在多CPU的环境中,这些线程是并发运行的。多线程就是在一个进程内有多个线程。从而使一个应用程序有了多任务的功能。多进程技术也可以实现这一点,但是创建进程的高消耗(每个进程都有独立的数据和代码空间),进程之间通信的不方便(消息机制),进程切换的时间太长,这些导致了多线程的提出,对于单CPU来说(没有开启超线程),在同一时间只能执行一个线程,所以如果想实现多任务,那么就只能每个进程或线程获得一个时间片,在某个时间片内,只能一个线程执行,然后按照某种策略换其他线程执行。由于时间片很短,这样给用户的感觉是同时有好多线程在执行。但是线程切换是有代价的,因此如果采用多进程,那么就需要将线程所隶属的该进程所需要的内存进行切换,这时间代价是很多的。而线程切换代价就很少,线程是可以共享内存的。所以采用多线程在切换上花费的比多进程少得多。但是,线程切换还是需要时间消耗的,所以采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。上述结果只是针对单CPU,如果对于多CPU或者CPU采用超线程技术的话,采用多线程技术还是会提高程序的执行速度的。因为单线程只会映射到一个CPU上,而多线程会映射到多个CPU上,超线程技术本质是多线程硬件化,所以也会加快程序的执行速度。

    ====================================================================================

    如果线程出现死锁,唯一能证明的就是应用程序有问题,这并不是线程的缺点。

    线程相对于进程的优点:
    1、开销小
    2、资源共享性好。

    线程相对于进程的缺点:
    1、共享资源需要耗费一定的锁资源,同步相对复杂。
    2、一个线程崩溃可能导致整个进程崩溃,这个当然是自己的应用程序有问题

    ====================================================================================

    CPU是以时间片的方式为进程分配CUP处理时间的,当一个进程以同步的方式去完成几件事情时,此进程必须完成了第一件事情以后再做第二件事,如此按顺序地向CPU请求完成要做的事情。在此单线程的工作模式下,如果把CUP看作是一共有100个时间片的话,CPU可能一直都只是花了其中的10个时间片来处理当前进程所要做的事情,只是用到了CPU的10%的时间片,而其他时间都白白浪费了,当然,实际上CPU的工作模式还是做完一件事以后再去做另一件事,只是CUP的处理速度非常快,很快就处理完成所请求的情事。

        为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而互不干扰,如当前进程要完成三件事情1、2、3,那么CPU会分别用10%的时间来同时处理这3件事情,从而让CPU的使用率达到了30%,大大地提高了CPU的利用率。多线程的好处在处理一些特殊的场合其优势尤其明显。比如下载文件,你要一边下载一边显示进度一边保存,在这种情况下,如果没有用多线程的话,没有意外的话一般都会把主线程阻塞,比如进度条的进度根本没有随着已下载的量而变化,堪至是整个窗体都动不了,用多线程就可以很好地解决这个问题。

        这里有一个生活实例可能更好地去理解多线程:你女朋友做饭,正常的话她都会把洗好的菜(肉)先放到锅里煮,然后一边洗别的菜或处理别的事情,如:洗碗、收拾桌台准备开饭,人还是一个人,但她同时做几件事情,这样就可以大大地提高效率。总的一句话就是:CPU还是要花同样多的时间去完成所有的事情,但多线程可以让CPU掺插地同时做多件事情,在视觉上让用户觉得计算机在同时帮他处理多件事情,更好地改善用户体验。

         了解了多线程的好处以后,就要了解应该在什么样的情况下使用多线程技术。因为并不是说所有情况下用多线程都是好事,因为多线程的情况下,CPU还要花时间去维护,CPU处理各线程的请求时在线程间的切换也要花时间,所以一般情况下是可以不用多线程的,用了有时反而会得不偿失。大多情况下,要用到多线程的主要是需要处理大量的IO操作时或处理的情况需要花大量的时间等等,比如:读写文件、视频图像的采集、处理、显示、保存等。

    展开全文
  • 为什么javascript是单线程

    万次阅读 多人点赞 2016-07-08 16:27:49
    今天面试的时候,面试官问了我这个问题,为什么javascript是单线程的?我的脑袋瞬间蒙了,我从单线程跟多线程的区别来回答:比如多线程要考虑线程之间的资源抢占,死锁,冲突之类的。回到学校后我就去找这个问题的...

    今天面试的时候,面试官问了我这个问题,为什么javascript是单线程的?我的脑袋瞬间蒙了,我从单线程跟多线程的区别来回答:比如多线程要考虑线程之间的资源抢占,死锁,冲突之类的。回到学校后我就去找这个问题的答案。下面分享一篇来自阮一峰老师的博客,原文地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html


    一、为什么JavaScript是单线程?

    JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

    JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

    为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完
    全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

    二、任务队列

    单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

    如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。

    JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。

    于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

    具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)

    1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
    (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
    (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
    (4)主线程不断重复上面的第三步。

    下图就是主线程和任务队列的示意图。
    这里写图片描述
    只要主线程空了,就会去读取”任务队列”,这就是JavaScript的运行机制。这个过程会不断重复。

    三、事件和回调函数

    “任务队列”是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在”任务队列”中添加一个事件,表示相关的异步任务可以进入”执行栈”了。主线程读取”任务队列”,就是读取里面有哪些事件。

    “任务队列”中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入”任务队列”,等待主线程读取。

    所谓”回调函数”(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。

    “任务队列”是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,”任务队列”上第一位的事件就自动进入主线程。但是,由于存在后文提到的”定时器”功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。

    四、Event Loop

    主线程从”任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。

    为了更好地理解Event Loop,请看下图。(转引自Philip Roberts的演讲《Help, I’m stuck in an event-loop》)

    这里写图片描述

    上图中,主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在”任务队列”中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取”任务队列”,依次执行那些事件所对应的回调函数。

    执行栈中的代码(同步任务),总是在读取”任务队列”(异步任务)之前执行。请看下面这个例子。

        var req = new XMLHttpRequest();
        req.open('GET', url);    
        req.onload = function (){};    
        req.onerror = function (){};    
        req.send();

    上面代码中的req.send方法是Ajax操作向服务器发送数据,它是一个异步任务,意味着只有当前脚本的所有代码执行完,系统才会去读取”任务队列”。所以,它与下面的写法等价。

     var req = new XMLHttpRequest();
        req.open('GET', url);
        req.send();
        req.onload = function (){};    
        req.onerror = function (){};   

    也就是说,指定回调函数的部分(onload和onerror),在send()方法的前面或后面无关紧要,因为它们属于执行栈的一部分,系统总是执行完它们,才会去读取”任务队列”。

    五、定时器

    除了放置异步任务的事件,”任务队列”还可以放置定时事件,即指定某些代码在多少时间之后执行。这叫做”定时器”(timer)功能,也就是定时执行的代码。

    定时器功能主要由setTimeout()和setInterval()这两个函数来完成,它们的内部运行机制完全一样,区别在于前者指
    定的代码是一次性执行,后者则为反复执行。以下主要讨论setTimeout()。

    setTimeout()接受两个参数,第一个是回调函数,第二个是推迟执行的毫秒数。

    console.log(1);
    setTimeout(function(){console.log(2);},1000);
    console.log(3);

    上面代码的执行结果是1,3,2,因为setTimeout()将第二行推迟到1000毫秒之后执行。

    如果将setTimeout()的第二个参数设为0,就表示当前代码执行完(执行栈清空)以后,立即执行(0毫秒间隔)指定的回调函数。

    
    setTimeout(function(){console.log(1);}, 0);
    console.log(2);

    上面代码的执行结果总是2,1,因为只有在执行完第二行以后,系统才会去执行”任务队列”中的回调函数。

    总之,setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在”任务队列”的尾部添加一个事件,因此要等到同步任务和”任务队列”现有的事件都处理完,才会得到执行。

    HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()。

    需要注意的是,setTimeout()只是将事件插入了”任务队列”,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。

    六、Node.js的Event Loop

    Node.js也是单线程的Event Loop,但是它的运行机制不同于浏览器环境。

    请看下面的示意图(作者@BusyRich)。

    这里写图片描述

    根据上图,Node.js的运行机制如下。

    1)V8引擎解析JavaScript脚本。
    (2)解析后的代码,调用Node API。
    (3)libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。
    (4)V8引擎再将结果返回给用户。

    除了setTimeout和setInterval这两个方法,Node.js还提供了另外两个与”任务队列”有关的方法:process.nextTick和setImmediate。它们可以帮助我们加深对”任务队列”的理解。

    process.nextTick方法可以在当前”执行栈”的尾部—-下一次Event Loop(主线程读取”任务队列”)之前—-触发回调函数。也就是说,它指定的任务总是发生在所有异步任务之前。setImmediate方法则是在当前”任务队列”的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像。请看下面的例子(via StackOverflow)。

    
    process.nextTick(function A() {
      console.log(1);
      process.nextTick(function B(){console.log(2);});
    });
    
    setTimeout(function timeout() {
      console.log('TIMEOUT FIRED');
    }, 0)
    // 1
    // 2
    // TIMEOUT FIRED

    上面代码中,由于process.nextTick方法指定的回调函数,总是在当前”执行栈”的尾部触发,所以不仅函数A比setTimeout指定的回调函数timeout先执行,而且函数B也比timeout先执行。这说明,如果有多个process.nextTick语句(不管它们是否嵌套),将全部在当前”执行栈”执行。

    现在,再看setImmediate。

    
    setImmediate(function A() {
      console.log(1);
      setImmediate(function B(){console.log(2);});
    });
    
    setTimeout(function timeout() {
      console.log('TIMEOUT FIRED');
    }, 0);

    上面代码中,setImmediate与setTimeout(fn,0)各自添加了一个回调函数A和timeout,都是在下一次Event Loop触发。那么,哪个回调函数先执行呢?答案是不确定。运行结果可能是1–TIMEOUT FIRED–2,也可能是TIMEOUT FIRED–1–2。

    令人困惑的是,Node.js文档中称,setImmediate指定的回调函数,总是排在setTimeout前面。实际上,这种情况只发生在递归调用的时候。

    
    setImmediate(function (){
      setImmediate(function A() {
        console.log(1);
        setImmediate(function B(){console.log(2);});
      });
    
      setTimeout(function timeout() {
        console.log('TIMEOUT FIRED');
      }, 0);
    });
    // 1
    // TIMEOUT FIRED
    // 2

    上面代码中,setImmediate和setTimeout被封装在一个setImmediate里面,它的运行结果总是1–TIMEOUT FIRED–2,这时函数A一定在timeout前面触发。至于2排在TIMEOUT FIRED的后面(即函数B在timeout后面触发),是因为setImmediate总是将事件注册到下一轮Event Loop,所以函数A和timeout是在同一轮Loop执行,而函数B在下一轮Loop执行。

    我们由此得到了process.nextTick和setImmediate的一个重要区别:多个process.nextTick语句总是在当前”执行栈”一次执行完,多个setImmediate可能则需要多次loop才能执行完。事实上,这正是Node.js 10.0版添加setImmediate方法的原因,否则像下面这样的递归调用process.nextTick,将会没完没了,主线程根本不会去读取”事件队列”!

    
    process.nextTick(function foo() {
      process.nextTick(foo);
    });

    事实上,现在要是你写出递归的process.nextTick,Node.js会抛出一个警告,要求你改成setImmediate。

    另外,由于process.nextTick指定的回调函数是在本次”事件循环”触发,而setImmediate指定的是在下次”事件循环”触发,所以很显然,前者总是比后者发生得早,而且执行效率也高(因为不用检查”任务队列”)。

    展开全文
  • 单线程与多线程的区别?

    千次阅读 2018-08-29 16:58:35
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。 什么是多线程? 多线程是指程序中包含多个执行流,即在一个程序中可以同时...

    什么是进程?
    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
    而一个进程又是由多个线程所组成的。


    什么是线程?
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,
    即不同的线程可以执行同样的函数。


    什么是多线程?
    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
    也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。


    多线程的好处:
    可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,
    这样就大大提高了程序的效率。 


    多线程的不利方面:
    线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 
    多线程需要协调和管理,所以需要CPU时间跟踪线程; 
    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
    线程太多会导致控制太复杂,最终可能造成很多Bug;


    多线程与单线程的区别
    生活举例
    你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。
    如果你一手接电话,一手打卡。就是多线程。
    2件事的结果是一样的。。你接了电话且打了卡。

     

    多线程处理的优点

    同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。例如,文字处理器应用程序在您处理文档的同时,可以检查拼写(作为单独的任务)。由于多线程应用程序将程序划分成独立的任务,因此可以在以下方面显著提高性能: 
    多线程技术使程序的响应速度更快,因为用户界面可以在进行其他工作的同时一直处于活动状态。 
    当前没有进行处理的任务可以将处理器时间让给其他任务。 
    占用大量处理时间的任务可以定期将处理器时间让给其他任务。 
    可以随时停止任务。 
    可以分别设置各个任务的优先级以优化性能。 

    是否需要创建多线程应用程序取决于多个因素。在以下情况下,最适合采用多线程处理:
    耗时或大量占用处理器的任务阻塞用户界面操作。 
    各个任务必须等待外部资源(如远程文件或 INTERNET 连接)。 

    例如,用于跟踪 WEB 页上的链接并下载满足特定条件的文件的 INTERNET 应用程序“ROBOT”。这种应用程序可以依次同步下载各个文件,也可以使用多线程同时下载多个文件。多线程方法比同步方法的效率高很多,因为即使在某些线程中远程 WEB 服务器的响应非常慢,也可以下载文件。

    下面是多线程的例子
    还在DOS时代,人们就在寻求一种多任务的实现。于是出现了TSR类型的后台驻留程序,比较有代表性的有SIDE KICK、VSAFE等优秀的TSR程序,这类程序的出现和应用确实给用户使用计算机带来了极大的方便,比如SIDE KICK,们编程可以在不用进编辑程序的状态下,一边编辑源程序,一边编译运行,非常方便。但是,DOS单任务操作系统的致命缺陷注定了在DOS下不可能开发出真正的多任务程序。进入WINDOWS3.1时代,这种情况依然没有根本的改变,一次应用只能做一件事。比如数据库查询,除非应用编得很好,在查询期间整个系统将不响应用户的输入。
     进入了WINDOWS NT和WINDOWS 9X时代,情况就有了彻底的改观,操作系统从真正意义上实现了多任务(严格地说,WIN9X还算不上)。一个应用程序,在需要的时候可以有许多个执行线程,每个线程就是一个小的执行程序,操作系统自动使各个线程共享CPU资源,确保任一线程都不能使系统死锁。这样,在编程的时候,可以把费时间的任务移到后台,在前台用另一个线程接受用户的输入。对那些对实时性要求比较高的编程任务,如网络客户服务、串行通信等应用时,多线程的实现无疑大大地增强了程序的可用性和稳固性。

    =====================================================================================

    坏处:增加了调度和管理的开销,带来了一些不确定性,需要复杂的同步机制,避免死锁等等。
    好处:一定程度上提高响应速度,在多核的情况下还是更能充分利用CPU资源的。

    =====================================================================================

    单线程的也就是程序执行时,所跑的程序路径(处理的东西)是连续顺序下来的,必须前面的处理好,后面的才会执行到。   
    (未细看)单线程和多线程的优缺点 - Daniel - 休子的博客       多线程嘛,举个例子也就是说程序可以同时执行2个以上相同类似的操作,比如一些搜索代理或者群发email的多线程软件,由于操作一次需要网络的返回信息   花的时间比较长,而对cpu来说却是空闲的,如果是一个一个顺序执行,那么搜索几千个IP就会花上好久好久。   而如果用多线程就可以在等待期间   加入其他的搜索,然后等待,这样可以提高效率。不过多线程和多进程公用一些资源时要考虑的问题好像也是一样的,对于一些公共资源或者公共变量的访问和修改时要注意特别的,需要一些锁定什么的,还有顺序问题的考虑。  
           多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O,OEMBIOS等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。每个程序执行时都会产生一个进程,而每一个进程至少要有一个主线程。这个线程其实是进程执行的一条线索,除了主线程外你还可以给进程增加其它的线程,也即增加其它的执行线索,由此在某种程度上可以看成是给一个应用程序增加了多任务功能。当程序运行后,您可以根据各种条件挂起或运行这些线程,尤其在多CPU的环境中,这些线程是并发运行的。多线程就是在一个进程内有多个线程。从而使一个应用程序有了多任务的功能。多进程技术也可以实现这一点,但是创建进程的高消耗(每个进程都有独立的数据和代码空间),进程之间通信的不方便(消息机制),进程切换的时间太长,这些导致了多线程的提出,对于单CPU来说(没有开启超线程),在同一时间只能执行一个线程,所以如果想实现多任务,那么就只能每个进程或线程获得一个时间片,在某个时间片内,只能一个线程执行,然后按照某种策略换其他线程执行。由于时间片很短,这样给用户的感觉是同时有好多线程在执行。但是线程切换是有代价的,因此如果采用多进程,那么就需要将线程所隶属的该进程所需要的内存进行切换,这时间代价是很多的。而线程切换代价就很少,线程是可以共享内存的。所以采用多线程在切换上花费的比多进程少得多。但是,线程切换还是需要时间消耗的,所以采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。上述结果只是针对单CPU,如果对于多CPU或者CPU采用超线程技术的话,采用多线程技术还是会提高程序的执行速度的。因为单线程只会映射到一个CPU上,而多线程会映射到多个CPU上,超线程技术本质是多线程硬件化,所以也会加快程序的执行速度。

    ====================================================================================

    如果线程出现死锁,唯一能证明的就是应用程序有问题,这并不是线程的缺点。

    线程相对于进程的优点:
    1、开销小
    2、资源共享性好。

    线程相对于进程的缺点:
    1、共享资源需要耗费一定的锁资源,同步相对复杂。
    2、一个线程崩溃可能导致整个进程崩溃,这个当然是自己的应用程序有问题

    ====================================================================================

    CPU是以时间片的方式为进程分配CUP处理时间的,当一个进程以同步的方式去完成几件事情时,此进程必须完成了第一件事情以后再做第二件事,如此按顺序地向CPU请求完成要做的事情。在此单线程的工作模式下,如果把CUP看作是一共有100个时间片的话,CPU可能一直都只是花了其中的10个时间片来处理当前进程所要做的事情,只是用到了CPU的10%的时间片,而其他时间都白白浪费了,当然,实际上CPU的工作模式还是做完一件事以后再去做另一件事,只是CUP的处理速度非常快,很快就处理完成所请求的情事。

        为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而互不干扰,如当前进程要完成三件事情1、2、3,那么CPU会分别用10%的时间来同时处理这3件事情,从而让CPU的使用率达到了30%,大大地提高了CPU的利用率。多线程的好处在处理一些特殊的场合其优势尤其明显。比如下载文件,你要一边下载一边显示进度一边保存,在这种情况下,如果没有用多线程的话,没有意外的话一般都会把主线程阻塞,比如进度条的进度根本没有随着已下载的量而变化,堪至是整个窗体都动不了,用多线程就可以很好地解决这个问题。

        这里有一个生活实例可能更好地去理解多线程:回去看你女朋友做饭,正常的话她都会把洗好的菜(肉)先放到锅里煮,然后一边洗别的菜或处理别的事情,如:洗碗、收拾桌台准备开饭,人还是一个人,但她同时做几件事情,这样就可以大大地提高效率。总的一句话就是:CPU还是要花同样多的时间去完成所有的事情,但多线程可以让CPU掺插地同时做多件事情,在视觉上让用户觉得计算机在同时帮他处理多件事情,更好地改善用户体验。

         了解了多线程的好处以后,就要了解应该在什么样的情况下使用多线程技术。因为并不是说所有情况下用多线程都是好事,因为多线程的情况下,CPU还要花时间去维护,CPU处理各线程的请求时在线程间的切换也要花时间,所以一般情况下是可以不用多线程的,用了有时反而会得不偿失。大多情况下,要用到多线程的主要是需要处理大量的IO操作时或处理的情况需要花大量的时间等等,比如:读写文件、视频图像的采集、处理、显示、保存等。

     

    原文转自:https://blog.csdn.net/u012134199/article/details/46290465

    展开全文
  • 单线程的一些小例子

    2020-08-26 02:27:53
    1.获取线程名 /* 线程的名称: 主线程: main 新线程: Thread-0,Thread-1,Thread-2 */ public class Demo01GetThreadName { public static void main(String[] args) { //创建Thread类的子类对象 MyThread mt =...
  • 在我们的业务开发中,在多线程的情况下始终会有资源的公用,就是共享资源的使用,这个时候我们怎么保证线程的安全性呢?我们模拟一下业务场景: 三个角色:Gute 相当于一个资源 调用一个方法pass 方法 User 是使用资源...
  • 单线程和多线程的区别

    千次阅读 2019-05-23 15:26:56
    前端精髓每日为你推送假设业务场景中有一组互不相关的任务需要完成,现行的主流方法有以下两种。单线程串行依次执行。多线程并行完成。如果创建多线程的开销小于并行执行,那么多线程...
  • 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。 什么是多线程? 多线程是指程序中包含多个执行流,即在一个程序中可以同时...
  • PHP是单线程还是多线程?

    万次阅读 2018-08-07 15:04:24
    多线程并不总是比单线程优,多线程可能会引入其他问题(例如:两个线程同时调用一个类里的同一个方法时,可能出现死锁的情况)。  你可以这样理解 对应一个客户的一个页面请求处理的php 是单线程处理的, 这样一来...
  • 单进程单线程的Redis如何能够高并发

    万次阅读 2017-08-16 18:34:59
    参考文档: (1)http://yaocoder.blog.51cto.com/2668309/888374 ... 采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗) (1)为什么不采用多进程或多线程处理? 多
  • CPU单线程性能排行榜/天梯图

    万次阅读 2017-03-06 23:33:17
    http://www.cpubenchmark.net/singleThread.html
  • 多线程为什么比单线程快呢?

    万次阅读 2016-06-05 12:53:46
    多线程为什么比单线程快呢?
  • 多线程同步与单线程异步对比

    千次阅读 2014-03-03 14:13:24
    阻塞与线程
  • VS多线程下如何调试单线程

    千次阅读 2018-11-07 23:46:32
    首先打开VS菜单栏-调试-窗口-线程 不想调试的线程直接冻结掉 如果只想调试一个线程就必须冻结掉其他线程,这样才不会有干扰,调试的时候不会乱跳喜欢的话点个赞
  • 例如:有的OS不支持内核级线程,这时候就要注意了,一个进程中的一个用户级线程有系统阻塞调用(例如,IO阻塞操作)的时候,这个进程中的其他用户级线程都回被阻塞住了,这时候就不如多进程,每个进程单线程来处理。...
  • 顺手写了个程序对比了一下多线程IO和单线程异步IO的性能差异。需要说明的是,Linux上目前的异步IO是由用户态线程模拟的。目前内核原生的AIO和glibc中的异步IO都有缺陷,libeio目前感觉比较好(因为nodejs在用)。...
  • 对于单核CPU下多线程程序在同一时间点都只能有一个线程运行,对于多核CPU可以实现真正的并发同步运行,这种说法正确吗? 另外在多线程的情况下使用互斥对象来实现线程同步,这样的话多线程程序的运行效率受影响吗?
  • 最近做有关于游戏服务器用单线程的好还是多线程的好的讨论 有同学问:服务端逻辑全单线程的模型,为了避免查询离线玩家数据造成阻塞,除了启动服务器全部加载以外还有更好的办法吗? 同学B: 单线程逻辑模型也属于...
  • 多线程与单线程的区别

    万次阅读 2007-03-17 18:19:00
    单线程(Thread)与多线程的区别 首先了解一下cpu,随着主频(cpu内核工作时钟频率,表示在CPU内数字脉冲信号震荡的速度,等于外频(系统基本时间)乘倍频)的不断攀升,X86构架的硬件逐渐成为瓶颈,最高为4G,事实...
  • 64位Win7中导入excel提示“因为 OLE DB 访问接口 'MICROSOFT.JET.OLEDB.4.0' 配置为在单线程单元模式下运行,所以该访问接口无法用于分布式查询。” 主要原因是因为安装了32位office2010引起的。 1、首先先卸载...
1 2 3 4 5 ... 20
收藏数 913,595
精华内容 365,438
关键字:

单线程