第一、Queue的使用
创建 queue队列对象
参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。
返回值q 是队列对象
具体使用程序如下:
步骤1:导入模块
from multiprocessing import Queue
步骤2:创建一个队列
q = Queue(3)#可接一个整数,表示队列的容量,如果省略则表示不设上限。
print(q.empty())#True
步骤3:往队列添加消息
格式:put(obj, block=True, timeout=None)
obj:消息对象
q.put('消息1')
print(q.empty())#False
print('~~~~~~~~~~q.qsize:',q.qsize())#1
q.put('消息2')
print(q.full())#False
q.put('消息3')
判断队列状态的方法
q.full()#判断队列是否满足,返回一个布尔值,表示当前队列是否满了。
print(q.full())#True
q.empty()#判断队列是否为空,返回一个布尔值,表示当前队列是否为空
q.qsize()#返回一个数值,表示当前队列的消息数量
步骤4:从队列中取消息
value = q.get()
print(value)#消息1
value = q.get()
print(value)#消息2
value = q.get()
print(value)#消息2
print(q.empty())#True
二、判断队列阻塞的方法
1.Queue的使用
步骤1:导入模块
from multiprocessing import Queue
步骤2:创建一个队列
q = Queue(3)#可接一个整数,表示队列的容量,如果省略则表示不设上限。
print(q.empty())#True
步骤3:往队列添加消息
格式:put(obj, block=True, timeout=None)
obj:消息对象
q.put('消息1')
print(q.empty())#False
print('~~~~~~~~~~q.qsize:',q.qsize())#1
q.put('消息2')
print(q.full())#False
q.put('消息3')
判断队列状态的方法
q.full()#判断队列是否满足,返回一个布尔值,表示当前队列是否满了。
q.empty()#判断队列是否为空,返回一个布尔值,表示当前队列是否为空
q.qsize()#返回一个数值,表示当前队列的消息数量
print(q.full())#True
步骤4:从队列中取消息
value = q.get()
print(value)#消息1
value = q.get()
print(value)#消息2
value = q.get()
print(value)#消息2
print(q.empty())#True
第三、多线程
进程是资源分配的最小单位,线程是CPU调度的最小单位(程序真正执行的时候调用的是线程),每一个进程中至少有一个线程。
下面是线程的程序:
from urllib import request
def downloader(url):
file_name = url.split('/')[-1]
response = request.urlopen(url)
content = response.read()
with open(file_name,'wb') as fp:
fp.write(content)
print('子线程任务完成!')
if __name__ == '__main__':
#主进程下面有一个主线程
url_list = [
'http://www.langlang2017.com/img/logo.png',
'http://www.langlang2017.com/img/langlang1.png'
]
#创建线程
thread_list = []
for url in url_list:
t = Thread(target=downloader,args=(url,))
t.start()#启动线程
thread_list.append(t)
for t in thread_list:
t.join()
print('~~~~~~主线程执行完成~~~~~~~')码片
四、 .如何统计线程数量
程序如下
from threading import Thread
import threading
import time
def sing():
for i in range(3):
print('唱第%d首歌'%(i))
time.sleep(1)
def dance():
for i in range(3):
print('跳第%d段舞'%(i))
time.sleep(1)
if __name__ == '__main__':
t1 = Thread(target=sing)
t2 = Thread(target=dance)
t1.start()
t2.start()
查看线程的数量, 至少得有一个主线程
while True:
count = len(threading.enumerate())
print('当前线程数量:',count)
if count <=1:
break
五、.线程实现的第二种方法
使用继承方式开启线程,步骤如下:
1.定义一个类继承threading.Thread类。
2.复写父类的run()方法。
from threading import Thread
class MyThread(Thread):
def __init__(self,url):
Thread.__init__(self)
self.url = url
def run(self):
print('线程的业务逻辑代码~')
if __name__ == '__main__':
t = MyThread()
t.start()
六、线程之间共享全局变量
from threading import Thread
from multiprocessing import Process
g_num = 100
def work1():
global g_num
for i in range(3):
g_num+=1
print('-----in work1,g_num is %d'%(g_num))
def work2():
global g_num
for i in range(3):
g_num += 1
print('-----in work2,g_num is %d'%(g_num))
if __name__ == '__main__':
p1 = Process(target=work1)
p1.start()
p2 = Process(target=work2)
p2.start()
由于多线程可以共享全局变量,所以g_num由原来的100变成了106
多进程之间内存独立,不能够共享全局变量。如果通信的话,使用Queue
七、线程非安全:共享全局变量的问题,造成的数据丢失
多线程开发的时候共享全局变量会带来资源竞争效果,也就是说线程可以对全局变量进行修改,可能会造成数据混乱。
其解决方案是加锁(互斥锁)
其步骤是:
第一:创建锁
mutex=Lock()
第二、锁定
mutex.acquire([blocking])
第三、释放
mutex.release()
from threading import Thread
from threading import Lock
g_num = 0
def work1():
global g_num
for i in range(1000000):
mutex.acquire()#加锁
g_num+=1
mutex.release()#解锁
def work2():
global g_num
for i in range(1000000):
mutex.acquire()#加锁
g_num+=1
mutex.release()#解锁
mutex = Lock()#创建锁
if __name__ == '__main__':
# work1()
# work2()
# print('g_num:',g_num)#2000000
t1 = Thread(target=work1)
t2 = Thread(target=work2)
t1.start()
t2.start()
t1.join()
t2.join()
print('g_num:', g_num)
锁的好处:
1.确保了某段代码只能有一个线程从头到尾完成执行。
2.阻止了多线程并发执行,包含锁的某段代码实际上是只能以单线程模式执行。
3.由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对对方的持有的锁时,可能会造成死锁
死锁
在多个线程共享资源的时候,如果两个线程分别占有一部分资源,并且同时等待对方的资源,就会造成死锁现象。
如果锁之间相互嵌套,就有可能出现死锁。因此尽量不要出现锁之间的嵌套。