当前位置: 首页 > news >正文

python进程|线程|协程

进程(Process)

  1)进程就是正在运行的程序,它是操作系统中,资源分配的最小单位

  (1)资源分配:分配的是cpu和内存等物理资源

  (2)进程号是进程的唯一标识

  2)同一个程序执行两次之后是两个进程

  3)进程和进程之间的关系: 数据彼此隔离,通过socket通信

获取进程id

import os
res = os.getpid() # 获取当前进行id (当前子进程)
print(res)
res = os.getppid() # 获取父进程id
print(res)

# result 
"""
13724
13800
"""

进程的基本用法

from multiprocessing import Process
import time
import os
def func():
    print("S2>>>当前子进程id:%s,它的父进程id:%s" %(os.getpid(),os.getppid()))

if __name__ == "__main__":
    print("S1>>>子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid()))
    p = Process(target=func) # 创建子进程 target = 函数 单独用一个进程去执行谁,去完成哪个任务
    p.start() # 调用子进程

# result
"""
S1>>>子进程id:7576,父进程id:13800
S2>>>当前子进程id:7100,它的父进程id:7576
"""

带有参数的函数

  异步程序:不等没一行代码执行完毕,就往下执行其它代码

from multiprocessing import Process
import time
import os
def func():
    for i in range(1,5):
        print("S2>>>当前子进程id:%s,它的父进程id:%s"%(os.getpid(),os.getppid()))

if __name__ == "__main__":
    print("S1>>>子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid()))
    p = Process(target=func)
    p.start()

    n = 5
    for i in range(1,n+1):
        print("*" * i )
        
# result 
"""
S1>>>子进程id:7928,父进程id:13800
*
**
***
****
*****
S2>>>当前子进程id:8112,它的父进程id:7928
S2>>>当前子进程id:8112,它的父进程id:7928
S2>>>当前子进程id:8112,它的父进程id:7928
S2>>>当前子进程id:8112,它的父进程id:7928
"""

进程之间数据,彼此隔离

from multiprocessing import Process
import time
import os
count = 99
def func():
    global count
    count += 1
    print("当前子进程id:%s"%(os.getpid()),count)

if __name__ == "__main__":
    p = Process(target=func)
    p.start()
    time.sleep(1) # 让子进程跑完,看是否通过子进程修改
    print("主进程",count)

# result 
"""
当前子进程id:1956 100
主进程 99
"""

多进程之间的并发

  多程序并发时,因为cpu的调度策略,任务的执行是互相抢占cpu资源的过程

from multiprocessing import Process
import time
import os
def func(args):
    print("S2>>>当前子进程id:%s,它的父进程id:%s"%(os.getpid(),os.getppid()))
    print("end>>>",args)

if __name__ == "__main__":
    for i in range(10):
        Process(target=func,args=(i,)).start()
    print("主进程执行结束...")
    
# result 
"""
主进程执行结束...
S2>>>当前子进程id:10376,它的父进程id:9932
end>>> 2
S2>>>当前子进程id:13476,它的父进程id:9932
end>>> 1
S2>>>当前子进程id:11812,它的父进程id:9932
end>>> 3
S2>>>当前子进程id:13936,它的父进程id:9932
end>>> 4
S2>>>当前子进程id:2384,它的父进程id:9932
end>>> 7
S2>>>当前子进程id:7024,它的父进程id:9932
end>>> 5
S2>>>当前子进程id:14284,它的父进程id:9932
end>>> 8
S2>>>当前子进程id:4816,它的父进程id:9932
end>>> 9
S2>>>当前子进程id:120,它的父进程id:9932
end>>> 6
S2>>>当前子进程id:8604,它的父进程id:9932
end>>> 0
"""

主进程和子进程之间的关系

(1)主进程执行完所有代码,等待子进程全部结束,再终止程序

(2)不等待,子进程变成僵尸用户,在后台不停运行,耗费资源

from multiprocessing import Process
import time
import os
def func(args):
    print("S2>>>当前子进程id:%s,它的父进程id:%s"%(os.getpid(),os.getppid()))
    time.sleep(0.1)
    print("end>>>",args)

if __name__ == "__main__":
    for i in range(10):
        Process(target=func,args=(i,)).start()
    print("主进程执行结束...")
    
# result 
"""
主进程执行结束...
S2>>>当前子进程id:10092,它的父进程id:6304
S2>>>当前子进程id:11220,它的父进程id:6304
S2>>>当前子进程id:12992,它的父进程id:6304
S2>>>当前子进程id:8384,它的父进程id:6304
S2>>>当前子进程id:3824,它的父进程id:6304
S2>>>当前子进程id:12880,它的父进程id:6304
S2>>>当前子进程id:6352,它的父进程id:6304
end>>> 0
end>>> 2
S2>>>当前子进程id:7160,它的父进程id:6304
end>>> 9
end>>> 7
S2>>>当前子进程id:6676,它的父进程id:6304
end>>> 5
end>>> 8
end>>> 3
S2>>>当前子进程id:7488,它的父进程id:6304
end>>> 1
end>>> 6
end>>> 4
"""

join

  等待子进程执行完毕之后,主进程再向下执行

基本用法

from multiprocessing import Process
import time
import os
def func():
    print("发送第一封邮件")

if __name__ == "__main__":
    p = Process(target=func)
    p.start()
    time.sleep(1)
    p.join() # 针对于p进程对象来说,必须等待p这个进程任务执行完毕之后,主进程的代码在向下执行
    print("发送第二封邮件")
    
# result 
"""
发送第一封邮件
发送第二封邮件
"""

多个子进程

  多个子进程通过join加阻塞,可以实现同步控制

from multiprocessing import Process
import time
import os
def func(index):
    print("第%s封邮件发送..."%(index))

if __name__ == "__main__":
    lst = [] # 初始化一个列表
    for i in range(5):
        p = Process(target=func,args=(i,))
        p.start()
        lst.append(p)
        p.join()

    # 循环列表中每一个进程,都加上join,保证每个子进程执行完毕,保证同步性
    for i in lst:
        i.join()
    print("发送最后一封邮件...")
    
# result 
"""
第0封邮件发送...
第1封邮件发送...
第2封邮件发送...
第3封邮件发送...
第4封邮件发送...
发送最后一封邮件...
"""

自定义类方式创建进程

基本用法

from multiprocessing import Process
import time
import os
class MyProcess(Process): # 必须继承父类Process
    def run(self): # 必须写成run方法
        print(">>>子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid()))

if __name__ == "__main__":
    p = MyProcess()
    p.start()
    print(">>>主进程id:%s"%(os.getpid()))
    
# result 
"""
>>>主进程id:9988
>>>子进程id:14248,父进程id:9988
"""

带参数子进程函数

from multiprocessing import Process
import time
import os
class MyProcee(Process):
    def __init__(self,arg):
        super().__init__() # 必须调用一下父类的构造方法
        self.arg = arg
    def run(self):
        print(">>>子进程id:%s,父进程id:%s"%(os.getpid(),os.getppid()))
        print(self.arg)

if __name__ == "__main__":
    lst = []
    for i in range(10):
        p = MyProcee("参数:%s"%(i))
        p.start()
        lst.append(p)

    for i in lst:
        i.join()
    print("最后打印子进程id",os.getppid())
    
# result 
"""
>>>子进程id:7488,父进程id:8596
参数:6
>>>子进程id:11300,父进程id:8596
参数:8
>>>子进程id:12048,父进程id:8596
参数:4
>>>子进程id:7868,父进程id:8596
参数:0
>>>子进程id:4792,父进程id:8596
参数:5
>>>子进程id:10764,父进程id:8596
参数:2
>>>子进程id:10852,父进程id:8596
参数:1
>>>子进程id:9348,父进程id:8596
参数:3
>>>子进程id:9860,父进程id:8596
参数:7
>>>子进程id:8956,父进程id:8596
参数:9
最后打印子进程id 13800
"""

并行和并发

(1)并行:一个cpu同一时间不停执行多个程序

(2)并发:多个cpu同一时间不停执行多个程序

cpu的进程调度方法

(1)先来先服务fcfs(first come first server):先来的先执行

(2)短作业优先算法:分配的cpu多,先把短的算完

(3)时间片轮转算法:每一个任务就执行一个时间片的时间.然后就执行其他的

(4)多级反馈队列算法

    越是时间长的,cpu分配的资源越短,优先级靠后,越是时间短的,cpu分配的资源越多

进程三状态图

(1)就绪(Ready)状态-->只剩下CPU需要执行外,其他所有资源都已分配完毕 称为就绪状态。

(2)执行(Running)状态 --> cpu开始执行该进程时称为执行状态

(3)阻塞(Blocked)状态 --> 由于等待某个事件发生而无法执行时,便是阻塞状态,cpu执行其他进程.例如,等待I/O完成input、申请缓冲区不能满足等

同步|异步/阻塞|非阻塞

场景在多任务中

  同步:必须等我这件事干完了,你在干,只有一条主线,就是同步

  异步:没等我这件事情干完,你就在干了,有两条主线,就是异步

  阻塞:比如代码有了input,就是阻塞,必须要输入一个字符串,否则代码不往下执行

  非阻塞:没有任何等待,正常代码往下执行

  同步阻塞:效率低,cpu利用不充分

  异步阻塞:比如socketserver,可以同时连接多个,但是彼此都有recv

  同步非阻塞:没有类似input的代码,从上到下执行.默认的正常情况代码

  异步非阻塞:效率是最高的,cpu过度充分,过度发热

守护进程

  可以给子进程贴上守护进程的名字,该进程会随着主进程代码执行完毕而结束(为主进程守护)

  (1)守护进程会在主进程代码执行结束后就终止

  (2)守护进程内无法再开启子进程,否则抛出异常(了解)

 基本用法

from multiprocessing import Process
import time
import os
def func():
    print("子进程start...")
    time.sleep(0.1)
    print("子进程end...")

if __name__ == "__main__":
    p = Process(target=func)
    p.daemon = True # 在start开始前设置该进程为守护进程
    p.start()
    print("主进程执行结束...")
    
# result 
"""
主进程执行结束...
"""

 多个子进程

  (1)当主进程里面的代码全部执行完毕,守护进程自动终止

  (2)func1是守护进程,func2是非守护进程

from multiprocessing import Process
import time
import os
def func1():
    count = 1
    while True:
        print("*" * count)
        time.sleep(0.5)
        count += 1

def func2():
    print("func2 start...")
    time.sleep(2)
    print("func2 end...")

if __name__ == "__main__":
    p1 = Process(target=func1)
    p1.daemon = True
    p2 = Process(target=func2)
    p1.start()
    p2.start()

    time.sleep(1)
    print("主进程代码执行完毕...")

# result
"""
func2 start...
*
**
主进程代码执行完毕...
func2 end...
"""

 守护进程应用--报活

from multiprocessing import Process
import time
import os
def alive():
    while True:
        print("一号服务主机ok...")
        time.sleep(1) # 相隔1秒报活

def func():
    print("一号服务主机负责统计日志信息")
    time.sleep(3)

if __name__ == "__main__":
    p1 = Process(target=alive)
    p1.daemon = True
    p1.start()
    p2 = Process(target=func)
    p2.start()
    p2.join() # join添加阻塞,join执行结束,代表服务统计功能失败
    print(" ... ")

# result
"""
一号服务主机ok...
一号服务主机负责统计日志信息
一号服务主机ok...
一号服务主机ok...
一号服务主机ok...
 ... 
"""

 锁(LOCK)

(1)lock.acquire() 上锁

(2)lock.release() 解锁

(3)同一时间允许一个进程上一把锁,就是lock。加锁可以保证多个进程修改同一块数据,同一时间只能有一个任务进行修改,即串行修改,速度慢,保证安全。

(4)同一时间允许多个进程上多把锁,就是信号量[Semaphore]

    信号量是锁的变形:实现是 计数器 + 锁,同时允许多个进程上锁

(5)互斥锁Lock:就是进程的互相排斥,谁先抢到资源,谁就上锁修改资源内容,保证数据的同步性

    多个锁一起上,不开锁,会造成死锁,上锁和解锁是一对

基本语法

import json,time
lock = Lock() # 创建一把锁
lock.acquire() # 上锁
print(123)
lock.release() # 解锁

死锁

  程序添加了阻塞,程序不能往下执行。下面代码程序阻塞,也不会打印111

lock = Lock() # 创建一把锁
lock.acquire() # 上锁
lock.acquire()
print(111)
lock.release() # 解锁

  抢票示例

from multiprocessing import Lock,Process
import time
count = 1
def get_ticket(person):
    global  count
    time.sleep(0.1)
    if count > 0:
        print("%s抢到票了..."%(person))
        count -= 1
    else:
        print("%s没有抢到票..."%(person))

# 定义一个函数来进行统一调用
def ticket(person,lock):
    print("%s 查询余票:%s"%(person,count)) # 查询余票
    lock.acquire()
    get_ticket(person)
    lock.acquire()

if __name__ == "__main__":
    lock = Lock()
    for i in range(10):
        p = Process(target=ticket,args=("person%s"%(i),lock))
        p.start()

# result
"""
person6 查询余票:1
person0 查询余票:1
person1 查询余票:1
person6抢到票了...
person4 查询余票:1
person9 查询余票:1
person3 查询余票:1
person8 查询余票:1
person2 查询余票:1
person7 查询余票:1
person5 查询余票:1
"""

信号量

  本质上就是锁,只不过可以控制锁的数量

from multiprocessing import Process, Semaphore
import os, time

def ktv(person, sem):
    sem.acquire()
    print("%s进入ktv开始唱歌" % (person))
    print(os.getpid())
    time.sleep(3)
    print("%s走出ktv离开歌房" % (person))
    sem.release()

if __name__ == "__main__":
    sem = Semaphore(1)
    for i in range(5):
        p = Process(target=ktv, args=("person%s" % (i), sem))
        p.start()

# result 
"""
person3进入ktv开始唱歌
15956
person3走出ktv离开歌房
person2进入ktv开始唱歌
14632
person2走出ktv离开歌房
person4进入ktv开始唱歌
9248
person4走出ktv离开歌房
person1进入ktv开始唱歌
8816
person1走出ktv离开歌房
person0进入ktv开始唱歌
12992
person0走出ktv离开歌房
"""

事件(Event)

(1)阻塞事件

    e = Event() 生成事件对象e

    e.wait() 动态给程序加阻塞,程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值是False],True不加阻塞

(2)控制这个属性的值

    set() 方法:将这个属性的值改成True

    clear() 方法:将这个属性的值改成False

    is_set() 方法:判断当前的属性是否为True  (默认上来是False)

基本语法

from multiprocessing import Process,Event
import time,random
e = Event()
print(e.is_set())
e.wait(1) # 最多阻塞时间为1秒
print(111)

# result 
"""
False
111
"""
from multiprocessing import Process,Event
import time,random
e = Event()
e.set() # 将内部属性改成True
e.wait()
print(111)
e.clear() # 将内部属性改成False
e.wait()
print(222)

# result 
"""
111
"""

模拟交通灯

  (1)两个信号灯会交替变换

from multiprocessing import Process,Event
import time,random
def traffic_light(e):
    print("红灯亮")
    while True:
        if e.is_set():
            time.sleep(1) # 当前绿灯,等待1秒
            print("红灯亮") # 等完1秒后,变成红灯
            e.clear()
        else:
            time.sleep(1) # 当前是红灯
            print("绿灯亮")
            e.set()
e = Event()
traffic_light(e)

  (2)模拟车遇到红灯停,绿灯行的操作

from multiprocessing import Process,Event
import time,random
def traffic_light(e):
    print("红灯亮")
    while True:
        if e.is_set():
            time.sleep(1) # 当前绿灯,等待1秒
            print("红灯亮") # 等完1秒后,变成红灯
            e.clear()
        else:
            time.sleep(1) # 当前是红灯
            print("绿灯亮")
            e.set()

def car(e,i):
    if not e.is_set():
        print("car%s在等待..."%(i))
        e.wait()
    print("car%s通行..."%(i))

if __name__ == "__main__":
    e = Event()
    lst = []
    p1 = Process(target=traffic_light,args=(e,))
    p1.daemon = True # 设置守护进程,小车跑完,交通灯终止
    p1.start()
    # 模拟通行
    for i in range(5):
        time.sleep(random.uniform(0,2)) # 随机停0-2秒
        p2 = Process(target=car,args=(e,i))
        p2.start()
        lst.append(p2) # 将进程添加到列表中
        for i in lst:
            i.join() # 等所有车跑完,终止交通灯;加一个等待
        print("程序结束...")

# result
"""
红灯亮
绿灯亮
car0通行...
程序结束...
红灯亮
car1在等待...
绿灯亮
car1通行...
程序结束...
car2通行...
程序结束...
红灯亮
car3在等待...
绿灯亮
car3通行...
程序结束...
car4通行...
程序结束...
"""

进程间通信IPC

(1)IPC Inter-Process Communication

(2)进程之间通信的两种机制:管道Pipe 队列 Queue

(3)put() 存放

(4)get() 获取

(5)get_nowait() 拿不到报异常

(6)put_nowait() 非阻塞版本的put

(7)q.empty() 检测是否为空

(8)full() 检测是否已经存满

基本语法

  (1)先进先出,后进后出

  (2)让进程之间形成数据之间的共享

from multiprocessing import Process,Queue
q = Queue()
q.put(1) # 把数据放到q队列中
res = q.get() # 把数据从队列中取出
print(res)
res = q.get() # 没有数据后会形成阻塞
res = q.get_nowait() # 没有数据,直接报错

queue指定队列长度

from multiprocessing import Queue
q = Queue(3)
q.put(1)
q.put(2)
q.put(3)
# q.put(4) # 存放值满了,阻塞
q.put_nowait(5) # 往队列中存值,满直接报错

 进程通信,依赖Queue

from multiprocessing import Queue,Process
# 子进程
def func(q):
    res = q.get() # 子进程获取数据
    print(res)
    q.put(1) # 子进程添加数据

if  __name__ == "__main__":
    q = Queue()
    p = Process(target=func,args=(q,))
    p.start()
    q.put(2) # 主进程添加数据
    p.join()
    res = q.get() # 主进程添加数据
    print(res)
    print("程序结束...")

# result
"""
2
1
程序结束...
"""

 生产者与消费者模型

如:1号进程负责爬取网页中内容,2号进程负责匹配提取网页中关键字

  1号进程可以看成一个生产者,2号进程可以看成一个消费者

from multiprocessing import Process,Queue
import os,random,time
# 消费者模型(负责取值)
def consumer(q,name):
    while True:
        food = q.get() # 拿出数据
        if food is None:
            break
        time.sleep(random.uniform(0.1,1))
        print("%s 吃了一个 %s"%(name,food))

# 生产者模型(负责存值)
def producer(q,name,food):
    for i in range(3):
        time.sleep(random.uniform(0.1,1))
        print("%s 生产了 %s,%s"%(name,food,i))
        q.put(food + str(i))

if __name__ == "__main__":
    q = Queue()
    c1 = Process(target=consumer,args=(q,"A"))
    c1.start()
    p1 = Process(target=producer,args=(q,"B","egg"))
    p1.start()
    p1.join()
    q.put(None)

# result 
"""
B 生产了 egg,0
A 吃了一个 egg0
B 生产了 egg,1
A 吃了一个 egg1
B 生产了 egg,2
A 吃了一个 egg2
"""

进程池

(1)开启过多的进程并不一定提高效率

     cpu负载任务过多,平均单个任务执行效率低,较低执行速度

(2)apply 开启进程,同步阻塞,每次都要等待当前任务完成之后,开启下一个进程

(3)apply_async 开启进程,异步非阻塞(主进程和子进程异步)

线程

(1)进程是资源分配的最小单位,线程是计算机中调度的最小单位

(2)线程的缘起

    资源分配需要分配内存空间,分配cpu,分配的内存空间存放着临时要处理的数据,如要执行的代码,数据。

(3)线程的特点

    轻量级,能干更多的活,一个进程中所有线程资源共享,一个进程至少一个线程工作

 一个进程可以有多个线程,共享一份资源

from threading import Thread
from multiprocessing import Process
import os,time,random
def func(num):
    time.sleep(random.uniform(0.1,1))
    print("子线程",num,os.getpid())

if __name__ == "__main__":
    for i in range(5):
        t = Thread(target=func,args=(i,))
        t.start()

# result 
"""
子线程 1 6348
子线程 3 6348
子线程 0 6348
子线程 4 6348
子线程 2 6348
"""

并发多进程线程对比

from threading import Thread
from multiprocessing import Process
import os,time,random
# 计算多线程时间
def func(i):
    # print("子线程",i,os.getpid())
    pass

if __name__ == "__main__":
    lst = []
    start_time = time.time()
    for i in range(100):
        t = Thread(target=func,args=(i,))
        t.start()
        lst.append(t)

    for i in lst:
        i.join()

    end_time = time.time()
    print("time:",end_time-start_time)

# result
"""
time: 0.02393651008605957
"""

 

from threading import Thread
from multiprocessing import Process
import os,time,random
def func(i):
    # print("子线程",i,os.getpid())
    pass

if __name__ == "__main__":
    lst = []
    start_time = time.time()
    for i in range(100):
        p = Process(target=func,args=(i,))
        p.start()
        lst.append(p)

    for i in lst:
        i.join()

    end_time = time.time()
    print("time:",end_time-start_time)

# result
"""
time: 13.565200328826904
"""

多线程共享同一份进程资源

from threading import Thread
from multiprocessing import Process
import os,time,random
num = 100
lst = []
def func(i):
    global num
    num -= 1

for i in range(100):
    t = Thread(target=func,args=(i,))
    t.start()
    lst.append(t)

for i in lst:
    i.join()

print(num)

# result
"""
0
"""

线程相关函数

(1)线程.is_alive() 检测线程是否仍然存在

(2)线程.setName() 设置线程名字

(3)线程。getName() 获取线程名字

(4)currentThread().ident 查看线程id

(5)enumerate() 返回目前正在运行的线程列表

(6)activeCount() 返回目前正在运行的线程数量

查看线程id

from threading import currentThread,Thread
import os
def func():
    print("子线程",currentThread().ident)
t = Thread(target=func)
t.start()
print("主线程",currentThread().ident,os.getpid())

# result 
"""
子线程 9952
主线程 912 13268
"""

enumerate()

from threading import currentThread,Thread,enumerate
import os,time
def func():
    print("子线程",currentThread().ident)
    time.sleep(0.5)

for i in range(5):
    t = Thread(target=func)
    t.start()
print(enumerate())
print(len(enumerate()))

# result 
"""
子线程 3668
子线程 5856
子线程 13288
子线程 6304
子线程 5496
[<_MainThread(MainThread, started 8644)>, <Thread(Thread-1, started 3668)>, <Thread(Thread-2, started 5856)>, <Thread(Thread-3, started 13288)>, <Thread(Thread-4, started 6304)>, <Thread(Thread-5, started 5496)>]
6
"""

activeCount()

from threading import currentThread,Thread,enumerate,activeCount
import os,time
def func():
    print("子线程",currentThread().ident)
    time.sleep(1)

for i in range(5):
    Thread(target=func).start()

print(activeCount())

# result 
"""
子线程 5168
子线程 3428
子线程 13808
子线程 11732
子线程 2756
6
"""

守护线程

  等待所有线程执行结束后自动结束,守护所有线程

from threading import currentThread,Thread,enumerate,activeCount
import os,time
def func1():
    while True:
        time.sleep(1)
        print("线程1")

def func2():
    print("线程2-start")
    time.sleep(2)
    print("线程2-end")

t1 = Thread(target=func1)
t1.setDaemon(True)
t1.start()
t2 = Thread(target=func2)
t2.start()
print("主线程执行结束...")

# result 
"""
线程2-start
主线程执行结束...
线程1
线程2-end
"""

线程的数据安全 依赖Lock

from threading import currentThread,Thread,enumerate,activeCount,Lock
import os,time
n = 0
def func1(lock):
    global n
    for i in range(1000):
        lock.acquire() # 上锁
        n -= 1
        lock.release() # 解锁

def func2(lock):
    global n
    for i in range(1000):
        with lock:
            n += 1

if __name__ == "__main__":
    lock = Lock()
    lst = []
    for i in range(5):
        t1 = Thread(target=func1,args=(lock,))
        t2 = Thread(target=func2,args=(lock,))
        t1.start()
        t2.start()
        lst.append(t1)
        lst.append(t2)

    for i in lst:
        i.join()
    print("主线程结束")
    print(n)

# result 
"""
0
"""

信号量

from threading import currentThread,Thread,enumerate,activeCount,Lock,Semaphore
import os,time,random
def func(i,sem):
    time.sleep(random.uniform(0.1,1))
    with sem:
        print(i)
        time.sleep(2)

if __name__ == "__main__":
    sem = Semaphore(5)
    for i in range(5):
        Thread(target=func,args=(i,sem)).start()

# result 
"""
2
1
0
4
3
"""

 

死锁,递归锁,互斥锁

 

线程队列

 

协程(gevent)

(1)协程也叫纤程,协程是线程的一种实现

    一条线程可以在多任务之间来回切换,对于cpu,操作系统协程不存在

(2)协程的实现

    协程记住任务执行到那个位置,并且实现安全的切换

    一个任务一旦阻塞,立刻切换到另一个任务继续执行,保证线程总是忙碌

(3)一个线程可以由多个协程实现,协程之间不会产生数据安全问题

(4)协程模块

    greenlet gevent的底层,协程,切换的模块

    gevent 直接用,gevent能提供更全面的功能

def gen():
    for i in range(5):
        yield i

mygen = gen()
for i in mygen:
    print(i)

# result 
"""
0
1
2
3
4
"""

协程改写生产者消费者模型

def producer():
    for i in range(5):
        yield i

def consumer():
    g = producer()
    for i in g:
        print(i)

consumer()

# result 
"""
0
1
2
3
4
"""

协程的具体实现

import time
from greenlet import greenlet


def eat():
    print("eat one")
    g2.switch()
    time.sleep(3)
    print("eat two")


def play():
    print("play one")
    time.sleep(1)
    print("playtwo")
    g1.switch()


g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch()

# result 
"""
eat one
play one
playtwo
eat two
"""

gevent不能识别阻塞

from gevent import monkey
# mokey.patch_all 可以把下面引入的所有模块中的阻塞,重新识别出来
monkey.patch_all()
import time
import gevent

def eat():
    print("eat one")
    time.sleep(1)
    print("eat two")
    
def play():
    print("play one")
    time.sleep(1)
    print("playtwo")

g1 = gevent.spawn(eat)
g2 = gevent.spawn(play)

g1.join()
g2.join()
print("主线程执行结束")

# result 
"""
eat one
play one
eat two
playtwo
主线程执行结束
"""

 

转载于:https://www.cnblogs.com/wangzihong/p/11405047.html

相关文章:

  • -Shell 命令行工具 Cmder Babun Zsh MD
  • Apache Kafka(五)- Safe Kafka Producer
  • vue项目-axios封装、easy-mock使用
  • 扫描器开发框架学习
  • Java多线程实现和JUC介绍
  • git commit撤回操作
  • 内存运行PE文件
  • Mysql数据库
  • Apache Kafka(六)- High Throughput Producer
  • 设计模式-策略模式
  • CTF 资源
  • hibernate的id生成策略
  • Apache Kafka(七)- Kafka ElasticSearch Comsumer
  • Apache Kafka(八)- Kafka Delivery Semantics for Consumers
  • liquibase 注意事项
  • CEF与代理
  • ES6核心特性
  • Golang-长连接-状态推送
  • Hibernate最全面试题
  • httpie使用详解
  • JavaScript 一些 DOM 的知识点
  • laravel 用artisan创建自己的模板
  • LeetCode算法系列_0891_子序列宽度之和
  • Python_网络编程
  • Python学习笔记 字符串拼接
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • web标准化(下)
  • 大快搜索数据爬虫技术实例安装教学篇
  • 技术发展面试
  • 如何设计一个比特币钱包服务
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 应用生命周期终极 DevOps 工具包
  • 7行Python代码的人脸识别
  • ​iOS安全加固方法及实现
  • ​第20课 在Android Native开发中加入新的C++类
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • $.ajax,axios,fetch三种ajax请求的区别
  • %@ page import=%的用法
  • (02)vite环境变量配置
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (23)Linux的软硬连接
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (二十四)Flask之flask-session组件
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (三)docker:Dockerfile构建容器运行jar包
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转)fock函数详解
  • (转)mysql使用Navicat 导出和导入数据库
  • (转载)利用webkit抓取动态网页和链接
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)