zoukankan      html  css  js  c++  java
  • 并发 多线程 异步 并行

    一 基本概念:

    并发:同时处理多件事情,在处理第一个请求时同时响应第二个请求;

    同步:同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行,同步 调用在继续之前等待响应或返回值。如果不允许调用继续,就说调用被阻塞 了

    异步:并发的一种形式,(1)它采用回调机制,避免产生不必要的线程。(2)多线程也可以成为实现程序异步的一种方式,在这里 异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段(这违反了异步操作的本质)

    多线程:并发的另一种形式,它采用多个线程来执行程序。对多个线程的管理使用了线程池。

    并行处理:把正在执行的大量任务,分割成小块分配个多个运行的线程,线程池是存放任务的队列,这个队列能根据需要自行调整。由此产生了并行处理这个概念,多线程的一种,而多线程是并发的一种

    二 多线程和异步对比:

    多线程和异步操作两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性

    线程的本质:

    线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入CPU资源来运行和调度

    异步操作的本质:

    所有的程序最终都会由计算机硬件来执行,所以为了更好的理解异步操作的本质,我们有必要了解一下它的硬件基础。 熟悉电脑硬件的朋友肯定对DMA这个词不陌生,硬盘、光驱的技术规格中都有明确DMA的模式指标,其实网卡、声卡、显卡也是有DMA功能的。DMA就是直 接内存访问的意思,也就是说,拥有DMA功能的硬件在和内存进行数据交换的时候可以不消耗CPU资源。只要CPU在发起数据传输时发送一个指令,硬件就开 始自己和内存交换数据,在传输完成之后硬件会触发一个中断来通知操作完成。这些无须消耗CPU时间的I/O操作正是异步操作的硬件基础。所以即使在DOS 这样的单进程(而且无线程概念)系统中也同样可以发起异步的DMA操作。

    异步优缺点:

    因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。当然异步操作也并非完美无暇。编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些出入,而且难以调试。

    多线程优缺点:

    多线程的优点很明显,线程中的处理程序依然是顺序执行,符合普通人的思维习惯,所以编程简单。但是多线程的缺点也同样明显,线程的使用(滥用)会给系统带来上下文切换的额外负担。并且线程间的共享变量可能造成死锁的出现

    两者适用范围:

    在了解了线程与异步操作各自的优缺点之后,我们可以来探讨一下线程和异步的合理用途。我认为:当需要执行I/O操作时,使用异步操作比使用线程+同步 I/O操作更合适。I/O操作不仅包括了直接的文件、网络的读写,还包括数据库操作、Web Service、HttpRequest以及.net Remoting等跨进程的调用。

      而线程的适用范围则是那种需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行。但是往往由于使用线程编程的简单和符合习惯,所以很多朋友往往会使用线程来执行耗时较长的I/O操作。这样在只有少数几个并发操作的时候还无伤大雅,如果需要处理大量的并发操作时就不合适了。

    实现异步的四种方式:http://www.cnblogs.com/DebugLZQ/archive/2012/11/02/2751272.html

     三 TPL:

    * TPL=>TASK Parallel Library 并行库,它是基于线程池的
    * 一种框架要使得并行执行不会产生太多的进程,能够保证工作量能够平均的分配到所有线程上,并且能够报告错误和产生可靠地结果,这就是并行库Task Parallel Library的工作
    * (1)到底创建多少个线程才合适
    * (2)线程如何同步访问结果集,例如多个线程同时访问list<T>,是非线程安全的,每一次对线程加锁代价又很高,会带来严重的性能瓶颈
    * (3)如何保证每个线程工作量的合理分配(尽可能的平分)
    * (4)如果某个线程中抛出了异常,我们怎么处理呢
    * (5)对于小的计算问题,创建那么多的线程是否值得。或者说,对于这种情况,在单一线程中同步执行这些计算操作是否更恰当,创建和销毁一个线程开销是很大的
    * (6)怎样保证我们不会垄断系统资源或者给计算机带来过大负担
    * 从手动的线程管理来看,最自然的就是线程池了。线程池能管理很多个线程。和手动创建一个线程来执行特定操作不同,我们将工作任务扔到线程池中,它会选择合适的线程,然后去执行我们给定的方法。
    * 线程池解决了上面列出的若干问题,线程池通过限制创建线程的总数,根据给定的工作量来决定创建合适的线程数量,降低了在极端情况下,如处理量比较少的情况下创建和销毁线程的开销,帮助我们解决了对系统资源的独占和过度使用。
    *
    * 任务并行化:
    * 任务并行化是指通过一系列API将大的任务分解成一系列小的任务,然后再多线程上并行执行
    * (TPL)并行库有一系列API能够基于线程池同时管理成千上万个任务。TPL的核心是System.Threading.Tasks类,他代表一个小的任务,“Task是一种对线程和线程池里面的工作项的一种结构话抽象,Task类提供了如下这些功能
    * (1)能够调度任务在非指定的线程上独立执行,要在特定的线程上执行给定任务需要通过task scheduler来确定,默认的task scheduler会将任务放到CLR的线程池中,但是有一些task scheduler可以将任务发送到特定的线程,如UI线程上。
    (2)能够等待任务结束,并获取执行的结果
    (3)能够提供一种机制,等待某一任务执行结束后立即执行继续的操作,通常我们称之为回调,但是在这里我们使用继续这一术语。
    (4)能够处理单一任务抛出的异常,甚至是有层次关系的任务在原始的线程上,或者是任何一个对任务结果会产生影响的异常。
    (5)在任务还没有开始的时候,可以取消任务,或者是在任务执行过程中,提交结束任务请求。
    * 控制并行化:
    * 注意:当处理的数据量比较少时,使用并行会将大部分的花费都耗在了创建task对象,将带对象放到线程池以及等待任务完成上,这些操作浪费的时间远远大于数据处理的时间;
    * 可能会出现并行运行比同步还要耗费更多时间的情况,所以要控制并行化.TPL默认启动5个线程,任务数小于5的话,启动任务数个线程。如果任务较多,TPL在初始化5个线程后,每隔100毫秒左右新增线程,直到达到最大线程数。如果新增线程的过程中有任务完成,那么就不会新增线程
    * 问题:线程数无法控制,容易造成高CPU,系统失去响应
    * (1)只要数组的大小大于某一个阈值,就采用并行版本,否则采用顺序执行的版本。
    (2)只要递归的深度小于某一阈值,采用并行版本,否则采用顺序执行版本。(这一点甚至要优先于第一条,除非哨兵元素一直恰好排在元素的中间。
    (3)只要需要执行的任务个数小于特定的阈值,采用并行版本,否则采用顺序执行版本(这一条在没有其他的限制并行化的原则下比如递归的深度以及输入的大小上

    四  异步编程: 

     

  • 相关阅读:
    springMVC系列之(四) spring+springMVC+hibernate 三大框架整合(转)
    Java Web项目运行流程
    唯一识别码——UUID
    Map解析
    前端小技巧总结(三)
    前端小技巧总结(二)
    React学习总结(二)
    前端小技巧总结(一)
    React 学习总结(一)
    关于Java一些好的博客链接:
  • 原文地址:https://www.cnblogs.com/shaner/p/5588565.html
Copyright © 2011-2022 走看看