进程、线程、协程

进程:正在运行的程序实例,是对资源管理的集合
线程:系统调度的最小单位,是对执行指令的集合
协程:用户态的线程,主动的协助式工作

对比:
1、进程不能单独运行,每个进程创建时都会主动创建一个子线程用来执行具体操作
2、单个进程中可以存在多个子线程,第一个创建的子线程为主线程,线程可以再创线程
3、单个进程中,所有线程都是平等的,共享同一块内存空间(进程内存空间)
4、启动线程比启动进程快,每个进程内存独立
5、创建子进程相当于克隆一份父进程的内存空间
6、进程间不能直接访问,除父进程访问子进程之外,其他进程间相互访问必须通过中间代理,但是同一进程中的所有线程都可以相互访问和操作。

一、协程
1、简介
协程是在一个线程执行过程中可以在一个子程序的预定或者随机位置中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。他本身是一种特殊的子程序或者称作函数
通过yeild实现的生产消费者模型就是典型的协程。
2、优点:
无须线程上下文切换的开销
无须数据操作锁定与同步的开销
方便切换控制流,简化编程模型
高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题,适用于处理高并发
3、缺点:
无法利用多核资源,协程的本质是个单线程,无法将CPU的多核用上
进行阻塞操作时,会阻塞掉整个程序
4、Greenlet(封装好的协程模块)
为了保证并发效果,遇到 IO操作就切换,操作完后切换回来,Greenlet实现了这一功能

greenlet.swith()    #主动式的切换

5、Gevent(自动切换)
Gevent封装了Greenlet并且将手动切换修改为了自动切换
可以轻松的通过Gevent实现并发同步或异步编程
二、多进程(multiprocessing)

p = multiprocessing.Process(target=func, args(i,))  #创建进程
# func函数中必须包含创建线程的操作

1、获取进程信息

name:调用进程的模块名称
os.getppid:父进程ID
os.getpid:子进程ID

2、进程间的数据交互
进程间的内存是独立的,必须通过中间件进行交互。
提供了三种方法:
队列(Queue)

import Queue

def func(q):
    q.put(value)  #将value放入队列中
q = Queue()
p = multiprocessing.Process(target=func, args(q))
p.start()
print q.get()    #取出value
p.join()  #等待进程执行结束

看上去像是数据共享,但实际上是克隆了一份Queue交给子进程,子进程将Queue序列化后交给中间件进行反序列化再交给其他进程。
管道(Pipes):
类似socket,建立一个沟通桥梁,两个进程分别在两端进行数据交互操作
数据共享(Manager)

import multiprocessing from Manager, Process
with Manager() as manager:
    d = manager.dict()      #生成一个可供多个进程间共享的字典

3、进程池(Pool)
由于创建子进程时就是克隆一份父进程的内存空间给子进程,操作时内存损耗过大,这时候就需要进程池来对进程数量进行限制。
进程池内部维护着一个序列,存储多个进程信息,调用进程时向进程池发起请求,如果进程池内没有可供使用的进程,则等待至有进程响应请求为止。

#方法有 appley(同步、串行) 、apply_async(异步、并行)
import multiprocessing import Pool
pool = Pool(process=num)  #num:进程池最大进程数量
for i in range(10):
    pool.apply_async(func=func, args=(i), callback=cbk)
    #func 进程操作指令,i参数, cbk 回调函数
p.close()    #程序结束前必须先关闭进程池,再join等待进程结束
p.join()    #进程池中进程执行完毕后退出

四、多线程(threading)
1、调用方法

threading.Thread(target=func, args(i,))  #直接创建线程
class MyThread(threading.Thread)  #类继承创建线程

2、使用for循环可以创建多个线程,每个创建的线程不会等待前一个线程执行完毕,线程是异步、并行的。
3、等待子线程执行结果的方法
队列(Queue)
作用:增加双方的效率,完成程序的解耦,松耦合。
队列是有序的,可以理解为一个存放线程的容器。

#三种形态
queue.Queue(maxsize=n)   #FIFO先入先出模式
queue.LifoQueue(maxsize=n)    #LIFO先入后出模式
queue.ProiorityQueue(maxsize=n)    #存储时可以指定优先级
#基本方法
q = queue.Queue(10)    #实例化队列对象
q.put()    #存放    
q.get()    #取出
q.size()   #查看大小
q.get_nowait()    #没有数据取出时弹出异常
q.put(1, value)  #指定优先级,1为优先等级,越小越高

join() 等待线程结束

t_objs = []    #创建用来存放线程的列表
for i in range(10):
    t = threading.Thread(target=func, args(i))
    t.start()
    t_objs.append(t)
print "现在活动的线程总数为:",threading.active_count()
for t in t_objs:
    t.join()    #t.wait等待线程执行结束后再结束进程

GIL全剧解释器锁
python可以创建多个线程并平均分布到计算机的多核中,但是同时只能有一核在处理数据。
GIL全局解释器锁保证了数据的统一,在多线程修改数据时,为了防止数据混乱,对多线程进行限制变为串行处理。
线程锁(threading.Lock互斥锁)
线程之间相互沟通,并保证同一时间只有一个线程在对数据进行修改

lock = threading.Lock()
lock.acquire()    #上锁,数据修改操作前
lock.release()    #解锁,数据修改操作后

递归锁(threading.RLock)
当设计多线程中存在多个互斥锁时,解锁就会混乱,这时候需要递归锁,从最底层锁一层一层向上解锁。
信号量(threading.BoundedSemaphore())
互斥锁只允许同一时间一个线程进行数据修改操作,而Semaphore允许多个。

semaphore = threading.BoundedSemaphore(num)  #最多num个
# 上锁与解锁与Lock,RLock一致

事件events(threading.Events())
控制线程之间的交互,就是设置一个全局变量,负责线程之间的通信。

events = threading.Events()      #声明
events.set()      #设置标志位
events.clean()  #清除标志位
events.is_set()    #检测标志位
events.wait()    #等待标志位设定后继续执行

生产消费者模型
在并发编程中,生产消费者模型可以解决大部分的并发问题。
该模式通过平衡生产线和消费线程的工作能力来提高整体的处理速度。

生产消费者模型是通过一个容器来解决生产消费的强耦合问题。
生产者和消费者之间无序彼此通信,而通过阻塞队列来进行通讯,生产者生产完成后无须等待消费者消费,直接丢给阻塞队列,消费者请求消费时也无须提醒生产者,直接从阻塞队列获取。阻塞队列形成了一个缓冲区,平衡了生产者和消费者的处理能力。

简单模型代码:

import queue
import threading
import time

q = queue.Queue(maxsize=10)
def produce(name):
    count = 1
    while True:
        q.put('馒头')
        print "%s生产馒头*1"%name
        count += 1
        time.sleep(1)

def consumer(name):
      while True:
          print "%s吃掉一个馒头"%name
          time.sleep(2)

p = threading.Thread(target=produce, args=('p01'))
c1 = threading.Thread(target=consumer, args=('c01'))
c2 = threading.Thread(target=consumer, args=('c02'))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容