python 协程

2019-10-19  本文已影响0人  nnnnxcj

线程Routine

线程是CPU进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程中可以并发多个线程,每条线程执行不同的任务。对于抢占式操作系统来说,当线程数越多时,CPU发生上下文切换的概率就越大,从而导致CPU占用很高,但是系统效率却上不去的问题。

多线程python实现

1.直接调用

import threading
import time

def print_time( threadName, delay):
   count = 0
   while count < 3:
      time.sleep(delay)
      count += 1
      print("%s: %s" % ( threadName, time.ctime(time.time())))

if __name__ == "__main__":
    t1=threading.Thread(target=print_time,args=("thread 1",3)) #生成线程实例
    t2=threading.Thread(target=print_time,args=("thread 2",1))

    t1.setName("aaa")   #设置线程名
    t1.start()  #启动线程
    t2.start()
    t2.join()   #join  等待t2先执行完
    print("end")
    print(t1.getName()) #获取线程名
'''
结果:
thread 2: Sat Oct 19 05:00:21 2019
thread 2: Sat Oct 19 05:00:22 2019
thread 1: Sat Oct 19 05:00:23 2019
thread 2: Sat Oct 19 05:00:23 2019
end
aaa
thread 1: Sat Oct 19 05:00:26 2019
thread 1: Sat Oct 19 05:00:29 2019
'''

2.继承式调用,重写init方法和run方法

import threading
import time

class MyThread(threading.Thread):
    def __init__(self,name,delay):
        threading.Thread.__init__(self)
        self.name = name
        self.delay = delay
    def run(self):
        print_time(self.name,self.delay)
        print("print one")
        time.sleep(3)

def print_time( threadName, delay):
   count = 0
   while count < 3:
      time.sleep(delay)
      count += 1
      print("%s: %s" % ( threadName, time.ctime(time.time())))

if __name__ == "__main__":
    t1=MyThread("thread 1",1)
    t2=MyThread("thread 2",2)
    t1.start()
    t2.start()
'''
结果:
thread 1: Sat Oct 19 05:15:40 2019
thread 2: Sat Oct 19 05:15:41 2019
thread 1: Sat Oct 19 05:15:41 2019
thread 1: Sat Oct 19 05:15:42 2019
print one
thread 2: Sat Oct 19 05:15:43 2019
thread 2: Sat Oct 19 05:15:45 2019
print one
'''

3.线程加锁

import threading
import time

num = 100 #设置一个共享变量
lock=threading.Lock()  #生成全局锁
def show():
    global num  #在函数内操作函数外变量,需设置为全局变量
    time.sleep(1)
    lock.acquire()  #修改前加锁
    num -= 1
    lock.release()  #修改后解锁
list=[]
for i in range(100):
    t = threading.Thread(target=show)
    t.start()
    list.append(t)

for t in list:
    t.join()

print(num)     #结果 0

4.Semaphore
同时允许一定数量的线程更改数据

import threading 
import time 

def run(n):
    semaphore.acquire()
    time.sleep(1) 
    print("run the thread: %s" %n)
    semaphore.release() 
if __name__ == '__main__':
    semaphore = threading.BoundedSemaphore(3) #设置最多允许3个线程同时运行
    for i in range(20):
        t = threading.Thread(target=run,args=(i,))
        t.start() 
while threading.active_count() != 1: 
    pass
else: 
    print('----done---')

5.event
实现两个或多个线程间的交互,提供了三个方法 set、wait、clear,默认碰到event.wait 方法时就会阻塞。
  event.set(),设定后遇到wait不阻塞
  event.clear(),设定后遇到wait后阻塞
  event.isSet(),判断有没有被设定

import threading 
def start(): 
    print("---start---1")
    event.wait() #阻塞
    print("---start---2") 
if __name__ == "__main__":
    event = threading.Event()
    t = threading.Thread(target=start)
    t.start()
    result=input(">>:") 
    if result == "set":
        event.set() #设定set,wait不阻塞
'''
结果:
---start---1

>>:set
---start---2
'''

协程Coroutine

又称微线程,是用户模式下的轻量级线程,它是程序语言利用逻辑在线程中创建的可以互相中断执行的代码段(个人理解),比如在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。但这一过程靠程序控制,但并不是函数调用(没有调用语句),这整个过程看似像多线程,然而协程只有一个线程执行。因此对比多线程,没有线程切换的开销,所以执行效率极高。

  1. yield协程
import time

def consumer():
    r = 'start'
    while True:
        n = yield r
        if not n:
            print("n is empty")
            continue
        print("消费了 %s" % n)
        r = "ok"

def producer(c):
    # 启动generator
    start_value = c.send(None)
    print(start_value)
    n = 0
    while n < 3:
        n += 1
        print("生产了 %d" % n)
        r = c.send(n)
        print(r)
    c.close()  # 关闭generator

c = consumer()  # 创建生成器
producer(c)  # 传入generator
'''
结果:
start
生产了 1
消费了 1
ok
生产了 2
消费了 2
ok
生产了 3
消费了 3
ok
'''
  1. greenlet协程,直接将函数包装成协程,需手动切换
from greenlet import greenlet
import random
import time

def producer():
    while True:
        item=random.randint(0,99)
        print("生产了 %s" %item)
        c.switch(item)  # 切换到消费者,并将item传入消费者
        time.sleep(1)
        
def consumer():
    while True:
        item=p.switch()   # 切换到消费者,并等待消费者传入item
        print("消费了 %s" %item)
        
c=greenlet(consumer)  # 将一个普通函数变成协程
p=greenlet(producer)
c.switch()  # 让消费者先进入暂停状态(只有恢复时才能接收数据)
'''
结果:
生产了 1
消费了 1
生产了 69
消费了 69
生产了 75
消费了 75
'''
  1. gevent协程,只在遇到阻塞时切换到另一个协程继续执行
from gevent import monkey
import gevent
from gevent.queue import Queue
import random
import time

queue=Queue(3)

def producer(queue):
    while True:
        item=random.randint(0,99)
        print("生产了 %s" %item)
        queue.put(item)
        # c.switch(item)  # 切换到消费者,并将item传入消费者
        time.sleep(1)
        
def consumer(queue):
    while True:
        item=queue.get()
        #item=p.switch()   # 切换到消费者,并等待消费者传入item
        print("消费了 %s" %item)
        
c=gevent.spawn(consumer,queue)  # 将函数封装成协程,并开始调度
p=gevent.spawn(producer,queue)

gevent.joinall([p,c])  # 阻塞(一阻塞就切换协程)等待

'''
结果:
生产了 29
生产了 52
生产了 14
生产了 45
消费了 29
消费了 52
消费了 14
生产了 17
生产了 61
生产了 41
消费了 45
消费了 17
消费了 61
'''
上一篇 下一篇

猜你喜欢

热点阅读