线程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(可以自由切换)。但这一过程靠程序控制,但并不是函数调用(没有调用语句),这整个过程看似像多线程,然而协程只有一个线程执行。因此对比多线程,没有线程切换的开销,所以执行效率极高。
- 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
'''
- 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
'''
- 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
'''