进程,线程和协程

Preliminary

进程(process)和线程(thread)是程序员必需掌握的核心知识。而多进程和多线程编程对于代码的并行并发执行,提升代码效率和缩短运行时间至关重要。

子程序和协程的区别及联系

  • 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。 所以子程序调用是通过栈实现的
  • 一个线程就是执行一个子程序。子程序调用总是一个入口,一次返回,调用顺序是明确的。
  • 协程的调用和子程序不同,协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序(不是函数调用,有点类似CPU的中断),在适当的时候再返回来接着执行。协程的特点在于是一个线程执行。不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。Python对协程的支持是通过generator实现的。如果进程池中的任务在执行过程中出现异常,程序不会报异常

进程,线程和协程的通俗描述

  • 有一个老板想要开个工厂进行生产某件商品(例如剪子), 他需要花一些财力物力制作一条生产线。这个生产线上有很多的器件等等资源称之为:进程(??计算机组成原理中进程的组成部分)

  • 只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程

  • 这个老板为了提高生产率,想到3种办法:

    1.在这条生产线上多招些工人,一起来做剪子,这样效率是成倍增长,即单进程多线程方式

    2.老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程多线程方式

    3.老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程), 为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事,或者再等待某些条件(比如等待另一个工人生产完某道工序之后,他才能再次工作), 那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式

简单总结

  1. 进程是资源分配的单位

  2. 线程是操作系统调度的单位

  3. 进程切换需要的资源很最大,效率很低

  4. 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)

  5. 协程切换任务资源很小,效率高

  6. 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中所以是并发

进程,线程和协程的通俗描述2

计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。
假定工厂的电力(共享资源)有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,因为(电力)资源有限,单个CPU一次只能运行一个任务(只能把有限资源分配给一个车间)。
编者注: 多核的CPU就像有了多个发电厂,使得多车间同时开工。

进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。
一个车间里,可以有很多工人。他们协同完成一个任务。

线程就好比车间里的工人。一个进程可以包括多个线程。
车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。
一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。
这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。
不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。

More??

  • 进程和线程的关系:进程获取系统分配的资源,主线程获取资源执行任务
  • 如果进程池中的任务在执行过程中出现异常,程序不会报异常????
  • 线程创建完不确定哪个子线程先执行
  • 单线程中,若调用start,则先执行主线程的,后执行子线程的,若调用run()方法,则相当于函数调用,按照程序的顺序执行
  • 线程之间的数据交互尽量使用 Queue,避免竞争
  • gevent有monkey.patch,gevent.sleep非阻塞式等待[greenlets,tornado,asyncio]
  • 在新开启一个子线程的时候,它默认是前台线程,只有将线程的setDaemon(True)方法调用后,它才是后台线程;
    当子线程是前台线程,主线程结束了并不影响其他子线程的执行,只有所有子线程都结束,程序就结束了;
    当子线程是后台线程,主线程结束了,会导致子线程被强迫结束,程序结束。

互斥锁

  • 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁
  • 可重入锁必须用在一个线程中,并且lock.acquire 和 lock.release 是配对的
  • 互斥锁为资源引入两种状态:锁定/非锁定,某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定",其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定"

互斥锁在Python中的实现

  • GIL 是python的全局解释器锁,同一进程中,假如有多个线程运行,一个线程在运行python程序的时候,会霸占python解释器,使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。
  • 多进程中,每个进程都分配一份独立的系统资源,相当于每个进程有了一个python解释器

Python多进程和多线程哪个快?

  • 对CPU密集型代码(比如循环计算??阿尔法狗下每一步棋子背后是由众多的服务器支持计算) - 多进程效率更高
  • 对IO密集型代码(比如文件操作,网络爬虫) - 多线程效率更高。
  • 为什么是这样呢?其实也不难理解。对于IO密集型操作,大部分消耗时间其实是等待时间,在等待时间中CPU因为阻塞是不需要工作的,那么为什么多线程会对IO密集型代码有用呢?这时因为python碰到等待会释放GIL供新的线程使用

Summary

  • 进程:资源消耗大,系统整体开销大,数据通信不方便
  • 线程:资源消耗小,可共享数据。上下文开销大。按时间片强制切换,不够灵活
  • 协程:内存开销更小,上下文切换开销更小。可根据事件切换,更加有效的利用CPU

Shoulders of Giants

协程----廖雪峰
IO密集型/CPU密集型, 多线程多进程介绍

进程与线程的一个简单解释

(部分内容摘录于网上,因为找不到来源,知道的小伙伴请留言)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值