关于如何加锁,获取钥匙,释放锁:
- lock = threading.Lock():生成锁对象,全局唯一;
- lock.acquire():获取锁。未获取到会阻塞程序,直到获取到锁才会往下执行;
- lock.release():释放锁,归回后,其他人也可以调用;
【注意事项】:lock.acquire() 和 lock.release()必须成对出现,否则就有可能造成死锁。
为了规避这个问题,可以使用使用上下文管理器来加锁。如下所示:
import threading lock = threading.Lock() with lock: # 这里写想要实现的代码 pass
关于GIL(全局锁):
任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。
【重点】python解释器中任意时刻都只有一个线程在执行;
关于Queue队列
谈及多线程,就不得不说Queue队列,这是从一个线程向另一个线程发送数据最安全的方式。创建一个被多个线程共享的 Queue 对象,这些线程通过使用put() 和 get() 操作来向队列中添加或者删除元素。
from queue import Queue # maxsize默认为0,不受限 # 一旦>0,而消息数又达到限制,q.put()也将阻塞 q = Queue(maxsize=0) # 阻塞程序,等待队列消息。 q.get() # 获取消息,设置超时时间 q.get(timeout=5.0) # 发送消息 q.put() # 等待所有的消息都被消费完 q.join() # 以下三个方法,知道就好,代码中不要使用 # 查询当前队列的消息个数 q.qsize() # 队列消息是否都被消费完,True/False q.empty() # 检测队列里消息是否已满 q.full()
关于线程池:
在Python3中,创建线程池是通过concurrent.futures函数库中的ThreadPoolExecutor类来实现的。
import Queue import threading import time ''' 这个简单的例子的想法是通过: 1、利用Queue特性,在Queue里创建多个线程对象 2、那我执行代码的时候,去queue里去拿线程! 如果线程池里有可用的,直接拿。 如果线程池里没有可用,那就等。 3、线程执行完毕,归还给线程池 ''' class ThreadPool(object): #创建线程池类 def __init__(self,max_thread=20):#构造方法,设置最大的线程数为20 self.queue = Queue.Queue(max_thread) #创建一个队列 for i in xrange(max_thread):#循环把线程对象加入到队列中 self.queue.put(threading.Thread) #把线程的类名放进去,执行完这个Queue def get_thread(self):#定义方法从队列里获取线程 return self.queue.get() def add_thread(self):#定义方法在队列里添加线程 self.queue.put(threading.Thread) pool = ThreadPool(10) def func(arg,p): print arg time.sleep(2) p.add_thread() #当前线程执行完了,我在队列里加一个线程! for i in xrange(300): thread = pool.get_thread() #线程池10个线程,每一次循环拿走一个!默认queue.get(),如果队列里没有数据就会等待。 t = thread(target=func,args=(i,pool)) t.start()
关于回调函数add_done_callback
回调函数是在调用线程完成后再调用的,在同一个线程中。
import requests import os import random import concurrent.futures as futures def download_img(url): resp = requests.get(url) filename = os.path.split(url)[1] # 获取文件名 with open(filename,'wb+') as f: f.write(resp.content) num = random.randint(2,5) print(filename + "generate:",num) time.sleep(num) return filename urls = ["http://pic27.nipic.com/20130320/8952533_092547846000_2.jpg", "http://pic19.nipic.com/20120212/9337475_104548381000_2.jpg",] ex = futures.ThreadPoolExecutor(max_workers = 3) res_iter = ex.map(download_img,urls) type(res_iter) for res in res_iter: print(res) def cf(rs): print(rs.result()) # [ex.submit(download_img,url).add_done_callback(cf) for url in urls] # for future in futures.as_completed(fu_tasks): for url in urls: f = ex.submit(download_img,url) f.add_done_callback(cf)
标签:thread,get,python,Queue,队列,线程,import,多线程 From: https://www.cnblogs.com/zhml/p/17346040.html