Pyton(八)2、进程、线程、协程 _ 复习归纳篇

一、自己的问题

1.为什么要有三个程,没有他们代码也可以执行呀!!

2.三者的区别及各自的优缺点。

3.三者的相关代码重新敲一遍。

可以浏览下面网址,作者详细阐明了三者的作用及区别。

http://blog.csdn.net/u012332571/article/details/53419216 

三个程的原理就是切换着去做所有的任务(比喻如下):

  假设你每天晚上需要做语文、数学、英语、物理、化学这5科的作业,每项作业耗时1小时。

      如果你先花1小时做语文作业,做完了,再花1小时做数学作业,这样,一次全部做完,一共花5小时,这种方式称为单任务模型,或者批处理任务模型。

  假设你打算切换到多任务模型,可以先做1分钟语文,再切换到数学作业,做1分钟,再切换到英语,以此类推,只要切换速度足够快,这种方式就和单核CPU执行多任务是一样的了,以幼儿园小朋友的         眼光来看,你就正在同时写5科作业。

  但是,切换作业是有代价的,比如从语文切到数学,要先收拾桌子上的语文书本、钢笔(这叫保存现场),然后,打开数学课本、找出圆规直尺(这叫准备新环境),才能开始做数学作业。操作系统在切       换进程或者线程时也是一样的,它需要先保存当前执行的现场环境(CPU寄存器状态、内存页等),然后,把新任务的执行环境准备好(恢复上次的寄存器状态,切换内存页等),才能开始执行。这个切       换过程虽然很快,但是也需要耗费时间。如果有几千个任务同时进行,操作系统可能就主要忙着切换任务,根本没有多少时间去执行任务了,这种情况最常见的就是硬盘狂响,点窗口无反应,系统处于假       死状态。所以,多任务一旦多到一个限度,就会消耗掉系统所有的资源,结果效率急剧下降,所有任务都做不好。

1.为什么要有三个程,没有他们代码也可以执行呀!!

答: 三个程的存在就是为了让函数同时执行,假如没有它们,func()函数要10分钟才执行完,func2()...以此类推,那么所有的函数执行完毕需要非常多的时间,

  有了三个程,就可以让他们同时执行,大大缩短了时间。

2.三者的不同及各自的优缺点。

 进程:数据之间不共享,每个进程都独占一份内存,最高效的工作方式是 进程数 == 计算机核数。

 线程:数据共享,适合IO密集型任务、cpu消耗少的任务,如web。

 协程(异步IO):数据共享,它就是一个线程,但是可以执行多个任务,没有切换的开销,不需要多线程的锁机制,也不存在变量冲突。

3.三程的代码

进程:

t = multiprocessing.Process()

t.start()

需要注意,在windows下面需要进行name的判断

import multiprocessing

a = 0
def f(b):
    global a
    a += b
    print(a)


if __name__ == '__main__':
    for iter in range(3):
        t = multiprocessing.Process(target=f,args=(1,))
        t.start()

"""
#输出结果
1
1
1

可以看出全局变量a的值并没有得到改变,说明他们之间的不存在共享
"""
进程基本操作

Manager的数据共享

#调用Manager 可以把任务中的数据放在里面,且它们是共享的。

from multiprocessing import Manager,Process
import time
def func(type,i):
    type.append(i)

if __name__ == '__main__':
    obj = Manager()
    lis = obj.list()
    #dic = obj.dict()
    #tup = obj.tuple()
    for iter in range(3):
        t = Process(target=func,args=(lis,iter))
        t.start()
        #t.join()   #等待任务全部执行完成,因为进程也是并发的所以,只有进程完全结束后,你才可以调用它们的结果。
    time.sleep(1)   #睡眠也是一样,当睡眠长度要超过执行的长度才可以取值成功。
    print(lis)
Manager的数据共享

线程:

t = threading.Thread()

t.start()

from threading import Thread
A = 0
def func(a):
    global A
    A = A + a
    print(A)

for iter in range(5):
    t = Thread(target=func, args=(iter,))
    t.start()


#从结果可以看出,线程之间的数据是共享的。
"""
输出结果
0
1
3
6
10
"""
线程基本操作

t.setDaemon()

#setDaemon(True) 时终止任务。
from threading import Thread
import time
def func(a):
    print("Hello",a)
    time.sleep(0.001)
    print("lazy boy",a)

for iter in range(10):
    t = Thread(target=func,args=(iter,))
    t.setDaemon(True)  #True False 两个必须填写一个,False代表什么也不干,True 表示执行
    t.start()
#从结果可以看出,setDaemon()t.qq.com 为True时,终止任务。
"""
输出结果:
Hello 0
Hello 1
Hello 2
Hello 3
Hello 4
Hello 5
Hello 6
Hello 7
Hello 8
lazy boy 1
lazy boy 0
Hello 9
"""
setDaemon终止任务

t.join()

from threading import Thread
import time
def func(a):
    print("Hello",a)
    time.sleep(1)
    print("lazy boy",a)

for iter in range(10):
    t = Thread(target=func,args=(iter,))
    t.start()
    t.join()
    
#函数一步一步的执行,让多线程毫无意义。
"""
输出结果
Hello 0
lazy boy 0
Hello 1
lazy boy 1
Hello 2
lazy boy 2
Hello 3
lazy boy 3
Hello 4
lazy boy 4
Hello 5
lazy boy 5
Hello 6
lazy boy 6
Hello 7
lazy boy 7
Hello 8
lazy boy 8
Hello 9
lazy boy 9
"""
join让线程无意义

Evnet()

#做用阻塞
from threading import Thread,Event
import time
def func(event,a):
    print("Hello")
    event.wait() #阻塞任务。
    print(a)

event_obj = Event()
for iter in range(10):
    t = Thread(target=func, args=(event_obj,iter))
    t.start()


inp = input(">>>")
if inp == "1":
    event_obj.set()
#从结果可以看出一旦下了命令,就开始执行被阻塞的任务。
#event_obj.clear() 清除set
"""
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
9
1
4
2
5
7
8
3
0
6
"""
Event 阻塞

线程锁

作用:假设列表A的所有元素就为0,当一个线程从前向后打印列表的所有元素,另外一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,一部分为1,这就导致了数据的不一致。锁的出现解决了这个问题。

#因为线程是并发的并且数据共享,如果多个线程同时对数据进行修改,就会产生脏数据,锁的出现就是为了,不让线程同时修改。
import threading
import time

globals_num = 0

lock = threading.RLock()


def Func():
    #lock.acquire()  # 获得锁
    global globals_num
    globals_num += 1
    time.sleep(1)
    print(globals_num)
    #lock.release()  # 释放锁


for i in range(10):
    t = threading.Thread(target=Func)
    t.start()
Rloack

queue 队列:

往队列里面放东西,put 往队列里面取东西 get   当队列放满时,会一直处于等待状态,利用并发,当管有空位置时,又开始放,取东西 当队列为空时,也会一直等待。

#队列就是好比一根管,可以往管里面放东先也可以取东西。
import queue,threading
q = queue.Queue(maxsize=3)  #为了0时队列长度无限,

q.put("你好")     #put方法是往队列里面放东西
q.put("xxx")      #全部存在管里面
q.put("xxx")      #当put的东西超出管的长度是会等待。
q.put("xxx")
for i in range(3):     #利用循环取出来
    g = q.get()         #get <= put 不等待
    print(g)            #get > put 等待
队列
原文地址:https://www.cnblogs.com/learn-python-M/p/6897354.html