多线程
创建线程
与创建进程类似
方式一
import threading import time def music(data): print("bengin listen music: {}".format(time.ctime())) time.sleep(1) print(str(data)) print("music end: {}".format(time.ctime())) def movie(data): print("bengin look movie: {}".format(time.ctime())) time.sleep(3) print(str(data)) print("movie end: {}".format(time.ctime())) th1 = threading.Thread(target=music, args=("love.mp3",)) #创建线程 th1.start() ##启动线程 th2 = threading.Thread(target=movie, args=("Anit.avi",)) th2.start()
方式二
通过继承Thread类,重写它的run方法
import threading import time class MultipleThreading(threading.Thread): def __init__(self, func, args=(), kwargs=None): threading.Thread.__init__(self) self.func = func self.args = args if kwargs is None: kwargs = {} self.kwargs = kwargs def run(self): ##重写run()方法 print('func_name is: {}'.format(self.func.__name__)) return self.func(*self.args, **self.kwargs) def music(data): print("bengin listen music: {}".format(time.ctime())) time.sleep(2) print(str(data)) print("music end: {}".format(time.ctime())) def movie(data): print("bengin look movie: {}".format(time.ctime())) time.sleep(5) print(str(data)) print("movie end: {}".format(time.ctime())) th1 = MultipleThreading(music, ("love.mp3",)) th2 = MultipleThreading(movie, ("Anit.avi",)) th1.start() th2.start()
join()方法
join()方法会阻塞主线程,当启动线程之后,只有线程全部结束,主线程才会继续执行,类似多进程
import threading import time def music(data): print("bengin listen music: {}".format(time.ctime())) time.sleep(2) print(str(data)) print("music end: {}".format(time.ctime())) def movie(data): print("bengin look movie: {}".format(time.ctime())) time.sleep(5) print(str(data)) print("movie end: {}".format(time.ctime())) thread_list = [] th1 = threading.Thread(target=music, args=("love.mp3",)) th2 = threading.Thread(target=movie, args=("Anit.avi",)) thread_list.append(th1) thread_list.append(th2) for th in thread_list: th.start() th.join() print("main thread continue: {}".format(time.ctime()))
守护线程
守护进程会随着主进程代码执行完后就结束
守护线程则会在主线程结束之后并且等待其他子线程结束后才结束
from threading import Thread
import time
def func1():
while True:
print('func1')
time.sleep(1)
def func2():
while True:
print('func2')
time.sleep(1)
t1 = Thread(target=func1,)
t1.daemon = True # 或者使用t1.setDaemon(True)
t1.start()
t2 = Thread(target=func2,)
t2.start()
print('主线程')
线程锁
互斥 Lock
from threading import Thread, Lock import time def func(lock): global n lock.acquire() temp = n time.sleep(1) n = temp - 1 lock.release()
n = 10 t_list = [] lock = Lock() for i in range(10): t = Thread(target=func, args=(lock,)) t.start() t_list.append(t) for t in t_list: t.join() print(n)
递归锁 RLock
一个线程可以多次acquire(),只要acquire()一次,其他线程就不能acquire(),所以,acquire() n 次后需要release() n 次其他线程才能acquire()。
通过RLock实现哲学家就餐:
from threading import RLock, Thread import time knife_lock = fork_lock = RLock() # 设置为同一个锁 def eat1(name): knife_lock.acquire() print('%s拿到刀子' % name) fork_lock.acquire() print('%s拿到叉子' % name) print('%s eating' % name) fork_lock.release() knife_lock.release() def eat2(name): fork_lock.acquire() print('%s拿到插子' % name) time.sleep(1) knife_lock.acquire() print('%s拿到刀子' % name) print('%s eating' % name) knife_lock.release() fork_lock.release() Thread(target=eat1, args=('1',)).start() Thread(target=eat2, args=('2',)).start() Thread(target=eat1, args=('3',)).start() Thread(target=eat2, args=('4',)).start()
信号量
在Python中存在两种信号量,一种就是纯粹的Semphore,还有一种就是BoundedSemaphore。
Semphore和BoundedSemaphore主要区别:
Semphore: 在调用release()函数时,不会检查,增加的计数是否超过上限(没有上限,会一直上升)
BoundedSemaphore:在调用release()函数时,会检查,增加的计数是否超过上限,这样就保证了使用的计数
Semphore示例
import threading import random semaphore = threading.Semaphore(0) ##信号量个数,默认值为1。 def producer(): global item item = random.randrange(1, 1000) semaphore.release() ## 信号量的 release() 可以提高计数器然后通知其他的线程, 信号量个数增加+1 print("producer notify : produced item number %s" % item) def consumer(): print("consumer is waiting....") global item semaphore.acquire(timeout=3) ##信号量个数减1 # 如果信号量的计数器到了0,就会阻塞 acquire() 方法, # 直到得到另一个线程的通知。如果信号量的计数器大于0,就会对这个值-1然后分配资源。 print("consume notify : consume item number %s" % item) if __name__ == "__main__": for i in range(3): th1 = threading.Thread(target=producer) th2 = threading.Thread(target=consumer) th1.start() th2.start() th1.join() th2.join() print("teminated")
BoundedSemaphore示例
import threading semaphore = threading.BoundedSemaphore(1) def func(num): semaphore.acquire() print("the number is: {}".format(num)) semaphore.release() # 再次释放信号量,信号量加一,这是超过限定的信号量数目,这时会报错ValueError: Semaphore released too many times semaphore.release() if __name__ == "__main__": num = 12 th1 = threading.Thread(target=func, args=(num,)) th1.start() th1.join()
使用条件condition控制线程数据同步
condition指的是应用程序状态的改变。这是另一种同步机制,其中某些线程在等待某一条件发生,其他的线程会在该条件发生的时候进行通知。一旦条件发生,线程会拿到共享资源的唯一权限。
Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。
from threading import Thread, Condition import random items = [] cond = Condition() class Producer(Thread): def __init__(self): Thread.__init__(self) def produce(self): global cond global items cond.acquire() if len(items) >= 2: print("items is 2, wait consume") cond.notify() ##当items数量不小于2时,通知consumer消费,线程阻塞 cond.wait() data = random.randrange(1, 1000) items.append(data) print("produce data is: {}".format(data)) print("increase items lenth to: {}".format(len(items))) cond.release() def run(self): for i in range(5): self.produce() class Consumer(Thread): def __init__(self): Thread.__init__(self) def consume(self): global cond global items cond.acquire() if len(items) <= 0: ##当items数量小于等于0时,通知producer产生数据,线程阻塞 print("items is 0, wait producer") cond.notify() cond.wait() data = items.pop() print("consume data is: {}".format(data)) print("decrease items lenth to: {}".format(len(items))) cond.release() def run(self): for i in range(5): self.consume() if __name__ == "__main__": producer = Producer() consumer = Consumer() producer.start() consumer.start() producer.join() consumer.join()
使用事件Event控制线程同步
Event是线程通信最为简单的机制,一个线程抛出一个信号,另外线程等待这个信号。
事件是线程之间用于通讯的对象。有的线程等待信号,有的线程发出信号。基本上事件对象都会维护一个内部变量,可以通过 set() 方法设置为 true ,也可以通过 clear() 方法设置为 false。 wait() 方法将会阻塞线程,直到内部变量为 true 。
Event(事件)处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么event.wait 方法时便不再阻塞。
Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态。当多个线程监听某一个触发条件时,如果全部线程都依赖这个触发条件,可以使用Event;如果需要精确控制某些线程被触发,则需要使用Condition。
Event class threading.Event :管理一个内部flag(True or False)
is_set() :判断内部flag是否True
set() :将内部flag设置为True,并通知所有处于等待阻塞状态的线程恢复运行状态。
clear() :将内部flag设置为False
wait(timeout=None) : 阻塞直到内部flag为True,或者timeout时间到。如果标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()。
from threading import Thread, Event import time class TrafficLight(Thread): def __init__(self, event, green_cnt, red_cnt): super(TrafficLight, self).__init__() self.event = event self.green_cnt = green_cnt self.red_cnt = red_cnt self.interval = self.green_cnt + self.red_cnt def run(self): count = 0 self.event.set() ##绿灯亮 while True: if count <= self.green_cnt: self.event.set() ##绿灯亮 print("绿灯亮了 {}s,请通行".format(count)) elif self.green_cnt < count <= self.interval: self.event.clear() ##红灯亮 print("红灯亮 {}s,车辆禁止通行".format(count)) elif count > self.interval: self.event.set() ##绿灯亮 count = 0 print("绿灯亮了 {}s,请通行".format(count)) time.sleep(1) count = count + 1 class Car(Thread): def __init__(self, event, car_name): super(Car, self).__init__() self.event = event self.car_name = car_name def run(self): while True: if self.event.is_set(): # 有标志位,代表是绿灯 print("{} is runnning".format(self.car_name)) time.sleep(1) else: # 如果不是绿灯就代表红灯 self.event.wait() ##阻塞,直到event被set才继续执行 print("{} is waiting".format(self.car_name)) if __name__ == "__main__": event = Event() thread_list = [] car_list = ["BMW", "Ford", "BenZ"] thread_light = TrafficLight(event, 1, 2) thread_list.append(thread_light) for car_name in car_list: car_th = Car(event, car_name) ##所有的车收到event事件同时开始执行/阻塞 thread_list.append(car_th) for th in thread_list: th.start() for th in thread_list: th.join()
使用栅栏Barrier控制数据同步
import threading from threading import Barrier, Thread def prepare_user_data(user): print("user {} is ready".format(user)) def prepare_car_data(car): print("car {} is ready".format(car)) def ready(): print("{} 数据准备好了".format(threading.current_thread().name)) class RunThreading(Thread): def __init__(self, barries, target=None, args=(), kwargs={}): super(RunThreading, self).__init__(target=None, args=args, kwargs=kwargs) self._barries = barries self.func = target self.args = args self._kwargs = kwargs def run(self): print("data prepare......") data = self.func(*self.args, **self._kwargs) self._barries.wait() return data if __name__ == "__main__": data = {"Leo": "沪111111", "Bruce": "沪222222", "Frank": "沪333333"} cnt = len(data) print("并发测试数据准备...") barrier = Barrier(cnt, action=ready, timeout=10) thread_list = [] for k, v in data.items(): thread_user = RunThreading(barrier, target=prepare_user_data, args=(k,)) thread_car = RunThreading(barrier, target=prepare_car_data, args=(v,)) thread_list.append(thread_user) thread_list.append(thread_car) for thread in thread_list: thread.start() for thread in thread_list: thread.join() if barrier.broken: print("数据准备出异常了,请重新准备数据")
使用Queue进行线程间数据通讯
线程之间如果要共享资源或数据的时候,可能变的非常复杂。Python的threading模块提供了很多同步原语,包括信号量,条件变量,事件和锁。如果可以使用这些原语的话,应该优先考虑使用这些,而不是使用queue(队列)模块。
Queue提供的一个线程安全的多生产者,多消费者队列,自带锁, 多线程并发数据交换必备。
生产者消费者问题:
from threading import Thread from queue import Queue import random, time class Producer(Thread): def __init__(self, queue): super(Producer, self).__init__() self.queue = queue def run(self): for i in range(10): item = random.randint(0, 256) self.queue.put(item) ##插入队列 print('Producer notify: item N° %d appended to queue by %s' % (item, self.name)) time.sleep(1) class Consumer(Thread): def __init__(self, queue): Thread.__init__(self) self.queue = queue def run(self): while True: item = self.queue.get() ##从队列中取出数据 print('Consumer notify : %d popped from queue by %s' % (item, self.name)) self.queue.task_done() if __name__ == '__main__': queue = Queue() thread_list = [] t1 = Producer(queue) t2 = Consumer(queue) t3 = Consumer(queue) thread_list.append(t1) thread_list.append(t2) thread_list.append(t3) for th in thread_list: th.start() for th in thread_list: th.join()
定时器Timer
与Thread类似,只是要等待一段时间后才会开始运行,单位秒。
import threading, time def data_ready(): print("data is ready at {}".format(time.ctime())) if __name__ == "__main__": th = threading.Timer(5, data_ready) th.start() while threading.active_count() > 1: print("数据还没ready:{}".format(time.ctime())) time.sleep(1)
线程池
import time from concurrent.futures import ThreadPoolExecutor # from concurrent.futures import ProcessPoolExecutor # 进程池用法与线程池完全相同 def func(n): time.sleep(0.5) print(n) return n*n t_pool = ThreadPoolExecutor(max_workers=5) # 一般不超过CPU*5 t_list = [] for i in range(20): t = t_pool.submit(func, i) t_list.append(t) t_pool.shutdown() # close()+join() print('主线程') for t in t_list: print(t.result())

浙公网安备 33010602011771号