进程、线程之间的关系
打个比方:如果有一个车间,车间里面有工人在工作。那么进程就相当于这个车间,而线程就相当于车间里面工作的工人。
是不是差不多明白点了。进程不能运行,它是一些资源的封装体,主要是cpu,io,内存资源,好比车间里的电和工具一样。每个进程要运行至少需要一个线程,这个线程就是主线程。线程是负责干具体的工作的。
单线程的例子:
import time
def eat(food):
print ("eat %s" %food)
print("start:", time.ctime())
time.sleep(2)
print (time.ctime())
def play(name):
print ("play %s" %name)
time.sleep(5)
print (time.ctime())
if __name__=="__main__":
eat("宫保鸡丁")
play("篮球")
print (time.ctime())
结果:
eat 宫保鸡丁
start: Wed Nov 29 21:05:26 2017
Wed Nov 29 21:05:28 2017
play 篮球
Wed Nov 29 21:05:33 2017
Wed Nov 29 21:05:33 2017
定义一个吃和玩的例子。可以看到,程序的运行的总时间是等于所以时间之和。
多线程例子:
import time
import threading
def eat(food):
print ("eat %s" %food)
print ("start:",time.ctime())
time.sleep(2)
print ("eat",time.ctime())
def play(name):
print ("play %s" %name)
time.sleep(5)
print ("play",time.ctime())
t1 = threading.Thread(target=eat,args=("宫保鸡丁",))
t2 = threading.Thread(target=play,args=("篮球",))
if __name__=="__main__":
t1.start()
t2.start()
print ("main:",time.ctime())
结果:
eat 宫保鸡丁
start: Wed Nov 29 20:58:48 2017
play 篮球
main: Wed Nov 29 20:58:48 2017
eat Wed Nov 29 20:58:50 2017
play Wed Nov 29 20:58:53 2017
可以看出,对比单线程。时间减少了2秒。
多线程的定义:
- 导入threading类
- t1 = threading.Thread(target=eat,args=(“宫保鸡丁”,)) 实例化Thread 类。target= 传入要执行的函数,args= 函数的参数。是一个元组。注意后面的逗号。
- t1.start() 运行这个线程
setDaemon守护线程
def eat(food):
print ("eat %s" %food)
time.sleep(2)
print ("eat",time.ctime())
def play(name):
print ("play %s" %name)
time.sleep(5)
print ("play",time.ctime())
threads = []
t1 = threading.Thread(target=eat,args=("宫保鸡丁",))
threads.append(t1)
t2 = threading.Thread(target=play,args=("篮球",))
threads.append(t2)
if __name__=="__main__":
t1.setDaemon(True)
t1.start()
t2.setDaemon(True)
t2.start()
print ("main:",time.ctime())
结果:
eat 宫保鸡丁
play 篮球
main: Thu Nov 30 09:46:38 2017
setDaemon是守护线程,就是守护着主线程。主线程退出子线程就跟着退出。
注意:setDaemon 在start之前
join等待子线程运行完再运行主线程
def eat(food):
print ("eat %s" %food)
time.sleep(2)
print ("eat",time.ctime())
def play(name):
print ("play %s" %name)
time.sleep(5)
print ("play",time.ctime())
threads = []
t1 = threading.Thread(target=eat,args=("宫保鸡丁",))
threads.append(t1)
t2 = threading.Thread(target=play,args=("篮球",))
threads.append(t2)
if __name__=="__main__":
for t in threads:
t.start()
for t in threads:
t.join()
print ("main:",time.ctime())
结果:
eat 宫保鸡丁
play 篮球
eat Thu Nov 30 09:48:21 2017
play Thu Nov 30 09:48:24 2017
main: Thu Nov 30 09:48:24 2017
可以看到主线程的main 最后执行。这里用循环,让两个子线程同时运行,运行完毕再运行主线程
内存共享 + 线程锁
num = 1
threads = []
lock = threading.Lock()
def add_num():
global num
lock.acquire()
num +=1
lock.release()
time.sleep(1)
for i in range(500):
t = threading.Thread(target=add_num)
t.start()
threads.append(t)
for t in threads:
t.join()
print (num)
结果:
501
内存共享是线程的一个特点,就是多个线程可以修改同一个内存数据。但是有时候会可能多个线程同时修改一个数据造成数据的不正确(在python2中出现过,不多。python3 没有出现)。为了保险起见可以在修改数据之前加一个锁(threading.Lock())。修改之后再释放锁来保证数据不会同时被多个线程占用。
threading.Event 线程事件(引用博友的代码了,写的挺好)
import threading,time
import random
def light():
if not event.isSet():
event.set() #wait就不阻塞 #绿灯状态
count = 0
while True:
if count < 10:
print('\033[42;1m--green light on---\033[0m')
elif count <13:
print('\033[43;1m--yellow light on---\033[0m')
elif count <20:
if event.isSet():
event.clear()
print('\033[41;1m--red light on---\033[0m')
else:
count = 0
event.set() #打开绿灯
time.sleep(1)
count +=1
def car(n):
while 1:
time.sleep(random.randrange(10))
if event.isSet(): #绿灯
print("car [%s] is running.." % n)
else:
print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
event = threading.Event()
Light = threading.Thread(target=light)
Light.start()
for i in range(3):
t = threading.Thread(target=car,args=(i,))
t.start()
event = threading.Event() 实例化一个事件
event.isSet()判断是否为True
even.set() 设置为True
even.clear() 设置为False
我觉得event就是设置了一个全局变量,每个线程根据变量的真假做动作。上面代码改为全局变量模式
import threading,time
import random
flag = True
def light():
global flag
if not flag:
flag = True #wait就不阻塞 #绿灯状态
count = 0
while True:
if count < 10:
print('\033[42;1m--green light on---\033[0m')
elif count <13:
print('\033[43;1m--yellow light on---\033[0m')
elif count <20:
if flag:
flag = False
print('\033[41;1m--red light on---\033[0m')
else:
count = 0
flag=True #打开绿灯
time.sleep(1)
count +=1
def car(n):
global flag
while 1:
time.sleep(random.randrange(10))
if flag: #绿灯
print("car [%s] is running.." % n)
else:
print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
#event = threading.Event()
Light = threading.Thread(target=light)
Light.start()
for i in range(3):
t = threading.Thread(target=car,args=(i,))
t.start()
多线程加queue实现生产者消费者模型。
模型简介:
生产者生产包子,消费者吃包子。如果生产者生产的慢,消费者吃得快。就会导致消费者的等待,在等待的过程中不能干别的事情。所以引入了queue,它就像一个桌子一样,生产完包子将包子放到桌子上,消费者直接去桌子上取。这样消费者不直接依赖生产者,也就实现了解耦。
上代码:
import queue
import threading
import time
q = queue.Queue()
def producer(name):
while True:
time.sleep(1)
q.put("包子")
print ("%s 做了一个包子" %name)
print (q.qsize())
def comsumer(name):
while True:
time.sleep(2)
if not q.empty():
q.get()
print("%s 吃了一个包子" %name)
for i in range(2):
t = threading.Thread(target=producer,args=("大壮",))
t.start()
for i in range(3):
t = threading.Thread(target=comsumer,args=("小壮实",))
t.start()