阿宁的Python学习-----线程、进程和协程

概念

从计算机硬件角度:

计算机的核心就是PCU,承担了所有的的计算任务。一个CPU,在一个时间切片里只能运行一个程序
在这里插入图片描述

一、线程

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

方法:

  • start 线程准备就绪,等待

  • setName 设置线程名称

  • getName 获取线程名称

  • setDaemon 把一个主进程设置为Daemon线程后,主线程执行过程中,后台线程也在进行,后台线程也在进行,主线程执行完毕后,后台不论执行完成都会停止

  • join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

  • run 线程被cpu调度后自动执行线程对象的run方法

threading模块

​ 线程的两种调用方式:

1、直接调用(常用)

import threading
import time
'''直接调用'''
def hello(name):
    print("hello %s"%name)
    time.sleep(3)
if __name__ == "__main__":
    t1 = threading.Thread(target=hello,args=("zhangsan",))  #生成线程实例
    t2 = threading.Thread(target=hello,args=("lisi",))

    t1.setName("aaa")  #设置线程名
    t1.start()   #启动线程
    t2.start()
    t2.join()   #等待t2执行完毕
    print("hello")
    print(t1.getName())  #获取线程名

2、继承式调用

import threading
import time
class MyThread(threading.Thread):
    def __init__(self,name):
        threading.Thread.__init__(self)
        self.name = name
    def run(self):
        print("hello %s"%self.name)
        time.sleep(3)
if __name__ =="__main__":
    t1 = MyThread("zhangsan")
    t2 = MyThread("lisi")
    t1.start()
    t2.start()

setDaemon线程

import threading
import time
def run(n):
    print("hello..[%s]\n"%n)
    time.sleep(2)
def main():
    for i in range(5):
        t = threading.Thread(target=run,args=[])
        t.start()
        t.join()
b = threading.Thread(target=main,args=[])
b.setDaemon(True)   #将主线程设置Daemon设置为True后,主线程执行完成时,其它子线程会同时退出,不管是否执行完任务
print("done")

进程

multiprocessing模块

进程调用

from multiprocessing import Process
import time
def start(name):
    time.sleep(1)
    print('hello',name)
if __name__ == '__main__':
    p = Process(target=start,args=('zhangsan',))
    p1 = Process(target=start,args=('lisi',))
    p.start()
    p1.start()
    p.join()

进程间通信

​ 每个进程都拥有自己的内存空间,因此不同进程内存空间是不共享的,要想实现两个进程间的数据交换,有几种办法

Queue(队列)
from multiprocessing import Process, Queue
def start(q):
    q.put('hello')
if __name__ =='__main__':
    q = Queue()
    p = Process(target=start,args=(q,))
    p.start()
    print(q.get())
    p.join()
Pipe(管道,不常用)

​ 把管道的两头分别赋给两个进程,实现两个进程的互相通信

from multiprocessing import Process,Pipe

def start(conn):
    conn.send('hello')  #发送
    print(conn.recv())  #接收
    conn.close()
if __name__ == '__main__':
    parent_conn, child_conn = Pipe()  #生成一个管道
    p = Process(target=start,args=(child_conn,))
    p.start()
    print(parent_conn.recv()) #接收
    parent_conn.send('111')   #发送
    p.join()
Manager(实现了进程间真正的数据共享)
from multiprocessing import Process, Manager
def f(dic, list,i):
    dic['1'] = 1
    dic['2'] = 2
    dic['3'] = 3
    list.append(i)

if __name__ == '__main__':
    manager = Manager()
    dic = manager.dict()#通过manager生成一个字典
    list = manager.list(range(5))#通过manager生成一个列表
    p_list = []
    for i in range(10):
        p = Process(target=f, args=(dic, list,i))
        p.start()
        p_list.append(p)
    for res in p_list:
        res.join()

    print(dic)
    print(list)
#输出结果
{'1': 1, '2': 2, '3': 3}
[0, 1, 2, 3, 4, 4, 9, 0, 7, 3, 6, 1, 5, 8, 2]
进程池

​ 进程池内部维护讴歌进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,知道进程池中有可用进程为止。

进程池有两个方法

1、apply(同步)

2、apply_async(异步)

from multiprocessing import Process,Pool
import time
def Foo(i):
    time.sleep(1)
    return i+100
def Bar(arg):
    print('number::',arg)

if __name__ == '__main__':
    pool = Pool(3)  #定义一个进程池,里面有三个进程
    for i in range(10):
        pool.apply_async(func=Foo, args=(i,),callback=Bar)

    pool.close()  #关闭进程池
    pool.join()   #进程池中进程执行完毕后再关闭(必须先close在join)
    
#输出结果
number:: 100
number:: 101
number:: 102
number:: 103
number:: 104
number:: 105
number:: 106
number:: 107
number:: 108
number:: 109
协程

协程又称微线程,是一种用户状态的轻量级线程。协成能保留上一次调用时的状态每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置,当程序众存在大量不需要CUP操作时(IO),适用于协程

协程有极高的执行效率,因为子程序切换不是线程切换,而是有程序自身控制,因此,没有线程切换的开销

不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多

因为协程是一个线程执行,所以想要利用多核CPU,最简单的方法是多进程+协程,这样既充分利用多核,又充分发挥协程的高效率。

那符合什么条件就能称之为协程:1、必须在只有一个单线程里实现并发 2、修改共享数据不需加锁 3、用户程序里自己保存多个控制流的上下文栈 4、一个协程遇到IO操作自动切换到其它协程

python中对于协程有两个模块,greenlet和gevent。

Greenlet(greenlet的执行顺序需要我们手动控制)
from greenlet import greenlet
def test1():
    print (11)
    gr2.switch()    #手动切换
    print (22)
    gr2.switch()

def test2():
    print (33)
    gr1.switch()
    print (44)

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

gevent(自动切换,由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成)

from gevent import monkey; monkey.patch_all()
import gevent
import time


def foo():
    print('11')
    time.sleep(3)
    print('22')

def bar():
    print('33')
    print('44')

gevent.joinall([
    gevent.spawn(foo),
    gevent.spawn(bar),
])

#输出结果  从结果可以看出,它是并发执行的
11
33
44
22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值