进程、线程和协程

 

进程是计算机中最小的资源分配单位

 

线程是进程中的一个单位,是计算机中能被CPU调度的最小单位

 

协程是一个比线程还小的单位

虽然上面说线程是能被调度的最小单位,但是协程不是操作系统可见的,是用户级的,是代码控制切换的 

 

进程

进程就是运行的程序,每一个进程在计算机中都有一唯一的进程id,这个id就是pid(process id)

os.getpid()  获取当前函数在进程中的pid

os.getppid() 获取当前进程的父进程的pid

进程可以 分成子进程,主进程和父进程。主进程是相对的,如果在进程中只看子进程,也可以把这个子进程当成父进程看

 

Process类是帮助启动\停止进程的   

用Process启动子进程

import os    
import time  
from multiprocessing import Process
def func(a,b,c):
    time.sleep(1)
    print(a,b,c,os.getpid(),os.getppid())   
if __name__ == '__main__':
if __name__ == '__main__':
    # windows操作系统下开启子进程子进程中的代码是通过import这种方式被导入到子进程中的
    print('主 :', os.getpid())
    Process(target=func,args=(1,2,3)).start()
    print('主 :', os.getpid())
    Process(target=func,args=(1,2,3)).start()
View Code

if __name__=='__main__'

进程中的其他几种方法

is_alive()  判断进程是否还‘活着’

terminate()  终止进程                        同步阻塞

 

开启多个子进程方法

多次执行Process方法就行

 

join()                                          同步阻塞

就是 阻塞住  需要等到对应的进程结束之后才能结束阻塞

import random
from multiprocessing import Process

def send_mail(name):
    time.sleep(random.uniform(1,3))
    print('已经给%s发送邮件完毕'%name)

if __name__ == '__main__':
    lst = ['li','zi','li','zi']
    # 阻塞等待一个子进程结束
    p = Process(target=send_mail, args=('alex',))
    p.start()
    p.join()   # 阻塞,直到p对应的进程结束之后才结束阻塞
    print('所有的信息都发送完毕了')
View Code

 

守护进程

守护进程是一个子进程守护主进程

https://www.cnblogs.com/lzlllll/articles/10732127.html

 

 

 使用面向对象的方式实现多进程

 

import os
from multiprocessing import Process
class MyProcess(Process):
    def run(self):   # 希望在子进程中执行的代码就放在run方法中
        print(os.getpid())

if __name__ == '__main__':
    for i in range(10):
        MyProcess().start()
View Code

想要传参数

import os
from multiprocessing import Process
class MyProcess(Process):
    def __init__(self,a,b):
        super().__init__()
        self.a = a
        self.b = b

    def run(self):   # 希望在子进程中执行的代码就放在run方法中
        print(os.getpid(),self.a,self.b)
        self.func()
if __name__ == '__main__':
    for i in range(10):
        MyProcess(1,2).start()   # 通知操作系统开进程,执行run方法
View Code


注意:一定是重写run方法

 

 

Lock类 锁

类似一个锁和钥匙的故事

lock.acquier()     获取钥匙

lock.release()      归还钥匙

锁的应用场景,当多个进程需要操作一个文件\数据的时候

保证对于数据的修改操作,同一时刻只能有一个执行

import json
import time
from multiprocessing import Process,Lock
def search_ticket(name):
    with open('ticket',encoding='utf-8') as f:
        dic = json.load(f)
        print('%s查询余票为%s'%(name,dic['count']))

def buy_ticket(name):
    with open('ticket',encoding='utf-8') as f:
        dic = json.load(f)
    time.sleep(2)
    if dic['count'] >= 1:
        print('%s买到票了'%name)
        dic['count'] -= 1
        time.sleep(2)
        with open('ticket', mode='w',encoding='utf-8') as f:
            json.dump(dic,f)
    else:
        print('余票为0,%s没买到票' % name)

def use(name,lock):
    search_ticket(name)
    print('%s在等待'%name)
    # lock.acquire()
    # print('%s开始执行了'%name)
    # buy_ticket(name)
    # lock.release()
    with lock:
        print('%s开始执行了'%name)
        buy_ticket(name)

if __name__ == '__main__':
    lock = Lock()
    l = ['a','b','c','d']
    for name in l:
        Process(target=use,args=(name,lock)).start()
View Code

 

 

 

互斥锁

互斥锁就是在同一个进程中 连续acquice多次产生死锁

死锁现象是acquice之后没有relrase 导致别的进程无法再继续进行

 

Queue类 队列

put() 传

get() 收# IPC锁   # 队列        # PUT       # GET   

生产者消费者模型 基于队列把生产数据和消费数据的过程分开了 #  #    
补充 #       
队列 是进程安全的 自带了锁
队列基于什么实现的 文件家族的socket服务
基于文件家族的socket服务实现的ipc机制不止队列一个,管道Pipe #        
队列 = 管道 + 锁      
管道 是基于文件家族的socket服务实现 # from multiprocessing import Pipe 

ipc是通过python的模块是实现的

基于原生的socket,基于进程队列的第三方软件/工具实现的

进程队列——进程安全

生产者和消费者模型

生产者    获取数据

消费者    处理数据

 

import time
import random
from multiprocessing import Process,Queue
def producer(q):
    for i in range(10):
        time.sleep(random.random())
        food = '泔水%s'%i
        print('%s生产了%s'%('taibai',food))
        q.put(food)

def consumer(q,name):
    while True:
        food = q.get()   # food = 食物/None
        if not food : break
        time.sleep(random.uniform(1,2))
        print('%s 吃了 %s'%(name,food))

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer,args=(q,))
    p1.start()
    c1 = Process(target=consumer,args=(q,'alex'))
    c1.start()
    c2 = Process(target=consumer,args=(q,'wusir'))
    c2.start()
    p1.join()
    q.put(None)
    q.put(None)
View Code


 

进程池

 

import os
import time
from concurrent.futures import ProcessPoolExecutor
def make(i):
    time.sleep(1)
    print('%s 制作螺丝%s'%(os.getpid(),i))
    return i**2

if __name__ == '__main__':
    p = ProcessPoolExecutor(4)   # 创建一个进程池
    for i in range(100):
        p.submit(make,i)   # 向进程池中提交任务
    p.shutdown()  # 阻塞 直到池中的任务都完成为止
    print('所有的螺丝都制作完了')
    p.map(make,range(100)) # submit的简便用法

    接收返回值
    ret_l = []
    for i in range(100):
        ret = p.submit(make,i)
        ret_l.append(ret)
    for r in ret_l:
        print(r.result())

    ret = p.map(make, range(100))
    for i in ret:
        print(i)
View Code

 


线程

也叫轻型进程

不做数据的隔离,在同一进程中的多个线程是可以共享一部分数据的

线程的开启\销毁\切换都比进程要高效很多

 

 

GIL锁 全局解释器锁

python当中的多线程,不能访问多个CPU,是python解释器导致的

 

from threading import Thread

开启线程

Thread(target=函数名,args=元祖)

 

IO操作  accept()负责从网络上读取数据  open() 调用操作系统的指令开启一个文件

 

import threading
# threading multiprocessing # 先有的threading模块
# 没有池的功能 # multiprocessing完全模仿threading模块完成的
# 实现了池的功能 # concurrent.futures # 实现了线程池\进程池

开启
import os
import time
from threading import Thread

def func():
    time.sleep(1)
    print('in func',os.getpid())

print('in main',os.getpid())
for i in range(20):
    # func()
    Thread(target=func).start()
View Code
传参数
import os
import time
from threading import Thread

def func(i):
    time.sleep(1)
    print('in func',i,os.getpid())

print('in main',os.getpid())
for i in range(20):
    # func()
    Thread(target=func,args=(i,)).start()
View Code
在线程部分不需要通过impotr来为新的线程获取代码
所以就不必要if __name__ == '__main__'
线程的其他方法
currentThread()
p=Thread(target=函数名,args=元祖)
currentThread()=p
得到的是当前所在线程的线程对象
p.name() 名字
p.ident() pid


active_count()
返回的是当前有多少个正在工作的线程
import os
from threading import Thread,currentThread
def func():
    t = currentThread()
    print(t.name,t.ident,os.getpid())

tobj = Thread(target=func)
tobj.start()
print('tobj :',tobj)
t2 = currentThread()
print(t2.name,t2.ident,os.getpid())
View Code

 


 



 


 

 

 

 

 

 

 

 

posted @ 2019-04-20 20:40  老李,向我开炮  阅读(265)  评论(0编辑  收藏  举报