#进程与线程的关系
"""
多进程(主进程,子进程):
优点:能同时利用多个CPU,进行多个操作,提高效率。
缺点:耗费内存资源(进程要开辟内存空间),进程不是越多越好,CPU个数 = 进程个数。
注意:进程创建内存空间,线程共享内存空间,进程里有全局解释器锁,进程中一次只应许一个线程被处理。
使用场景:计算密集型适合多进程。
多线程(主线程,子线程):
优点:共享内存,IO操作时(不用CPU),创造并发操作(多个操作同时进行),提高效率。
缺点:抢占资源,请求上下文切换非常耗时(线程处理切换后找到上次处理的地方),线程不是越多越好,视具体案例而定。
注意:在计算机中,执行任务的最小单元就是线程。
使用场景:IO密集型适合多线程。
"""
"""
队列queue
先进先出,一边放,另一边取
可设置最大个数,get等待,get_nowait不等待
"""
"""
使用线程
1、创建线程
import threading
import time
def f1():
pass
def f2(a1, a2):
time.sleep(10)
pass
t = threading.Thread(target=f1, args=(11,22,33))
t.start() # 线程开始跑,创建的是子线程
2、线程锁
防止出现脏数据,一个线程读取数据并对其加锁,CPU切换线程后其他线程不能读取数据,
3、线程池
Python内部没有提供线程池,需要自定义
"""
import threading
import time
def f1():
pass
def f2(a1, a2):
time.sleep(10)
pass
t1 = threading.Thread(target=f2, args=(11, 22))
t1.setDaemon(True) # 主线程是否等待子线程
t1.start() # 线程开始跑,创建的是子线程
print("第一次等待中")
t1.join(2) # 主线程等待子线程多久,不加参数无限等待
t2 = threading.Thread(target=f2, args=(11, 22))
t2.setDaemon(True)
t2.start() # 线程开始跑,创建的是子线程
print("第二次等待中")
t2.join(2) # 主线程等待子线程的执行的最多等待时间,超过时间,主线程继续执行下一部分
t3 = threading.Thread(target=f2, args=(11, 22))
t3.setDaemon(True) # 主线程执行完(解释器执行代码),是否等待子线程执行完再关闭,True:不等待:False:等待。默认为False
t3.start() # 线程开始跑,创建的是子线程
线程event
#!/usr/bin/env python # -*- coding;utf-8 -*- """ 线程event """ import threading import time def do(event): print("线程前半部分") event.wait() # 阻塞(十字路口),红灯则等待,绿灯则继续执行 print("线程后半部分") event_obj = threading.Event() for i in range(10): t = threading.Thread(target=do, args=(event_obj,)) t.start() # 耗时十分钟 # time.sleep(10) event_obj.clear() # 让灯变红 inp = input("请输入内容:>>>") if inp == "true": event_obj.set() # 让灯变绿,线程就都可以继续执行
线程数据共享
#!/usr/bin/env python # -*- coding;utf-8 -*- """ 默认情况下线程数据不共享 线程与线程之间数据可以共享 """ from threading import Thread li = [] def foo(i): li.append(i) print("hello", li) if __name__ == "__main__": for i in range(10): t = Thread(target=foo, args=(i,)) t.start()
线程池
- 简单线程池
#!/usr/bin/env python # -*- coding;utf-8 -*- """ 自定义线程池博客园教程地址 http://www.cnblogs.com/wupeiqi/articles/4839959.html """ import queue import threading import time class ThreadPool(object): def __init__(self, max_num=20): self.queue = queue.Queue(max_num) for i in range(max_num): self.queue.put(threading.Thread) def get_thread(self): return self.queue.get() def add_thread(self): self.queue.put(threading.Thread) def func(i, arg): print(i) time.sleep(4) # 在队列中增加线程类 arg.add_thread() if __name__ == "__main__": # 在队列中创建线程类 pool = ThreadPool(10) for i in range(30): # 获得类 thread = pool.get_thread() # 对象 = 类() ret = thread(target=func, args=(i, pool)) ret.start()
- 高级线程池
#!/usr/bin/env python # -*- coding;utf-8 -*- import threading import time import queue import contextlib StopEvent = object() class Threadpool(object): def __init__(self, max_num): self.max_num = max_num # 创建任务队列 self.queue = queue.Queue() self.terminal = False # 表示真实创建的线程列表 self.generate_list = [] # 表示空闲的线程列表 self.free_list = [] def run(self, func, args, callback=None): """ 线程池执行一个任务 :param func: 执行任务的函数 :param args: 任务函数的参数(以元组形式存在的任务包,封装了几个参数) :param callback: 任务执行失败或者成功后执行的回调函数,回调函数有两个参数 :return: """ # 往任务队列里加任务 w = (func, args, callback) self.queue.put(w) # 如果空闲线程等于零并且真实创建的线程数小于任务数 if len(self.free_list) == 0 and len(self.generate_list) < self.max_num: self.generate_thread() def generate_thread(self): """ 创建一个线程 :return: """ t = threading.Thread(target=self.call) t.start() def call(self): """ 循环去获取任务函数并执行任务函数 :return: """ current_thread = threading.current_thread() self.generate_list.append(current_thread) # 去任务并执行 event = self.queue.get() while event != StopEvent: # 如果是元组任务,解开任务包,执行任务 func, args, callback = event try: ret = func(*args) success = True except Exception as e: success = False ret = e if callback is not None: try: callback(success, ret) except Exception as e: pass with self.work_station(self.free_list, current_thread): if self.terminal: event = StopEvent else: event = self.queue.get() else: self.generate_list.remove(current_thread) def close(self): # 中途终止线程 num = len(self.generate_list) while num: self.queue.put(StopEvent) num -= 1 def terminate(self): # 终止线程(不清空队列),线程一直在等待拿,程序不会退出 """ 终止线程(清空队列) while self.generate_list: self.queue.put(StopEvent) """ self.terminate = True max_num = len(self.generate_list) # self.queue.empty() while max_num: max_num = len(self.generate_list) max_num -= 1 #self.queue.empty() @contextlib.contextmanager def work_station(self, station, val): station.append(val) try: yield finally: station.remove(val) def work(i): # time.sleep(3) print(i) pool = Threadpool(10) for i in range(50): pool.run(func=work, args=(i,), callback=None) # pool.terminate() pool.close()
- 绝版线程池
#!/usr/bin/env python # -*- coding;utf-8 -*- """ 自定义线程池博客园教程地址 http://www.cnblogs.com/wupeiqi/articles/4839959.html """ import queue import threading import contextlib import time StopEvent = object() class ThreadPool(object): def __init__(self, max_num, max_task_num = None): if max_task_num: self.q = queue.Queue(max_task_num) else: self.q = queue.Queue() self.max_num = max_num self.cancel = False self.terminal = False self.generate_list = [] self.free_list = [] def run(self, func, args, callback=None): """ 线程池执行一个任务 :param func: 任务函数 :param args: 任务函数所需参数 :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数) :return: 如果线程池已经终止,则返回True否则None """ if self.cancel: return if len(self.free_list) == 0 and len(self.generate_list) < self.max_num: self.generate_thread() w = (func, args, callback,) self.q.put(w) def generate_thread(self): """ 创建一个线程 """ t = threading.Thread(target=self.call) t.start() def call(self): """ 循环去获取任务函数并执行任务函数 """ current_thread = threading.currentThread() self.generate_list.append(current_thread) event = self.q.get() while event != StopEvent: func, arguments, callback = event try: result = func(*arguments) success = True except Exception as e: success = False result = None if callback is not None: try: callback(success, result) except Exception as e: pass with self.worker_state(self.free_list, current_thread): if self.terminal: event = StopEvent else: event = self.q.get() else: self.generate_list.remove(current_thread) def close(self): """ 执行完所有的任务后,所有线程停止 """ self.cancel = True full_size = len(self.generate_list) while full_size: self.q.put(StopEvent) full_size -= 1 def terminate(self): """ 无论是否还有任务,终止线程 """ self.terminal = True while self.generate_list: self.q.put(StopEvent) self.q.queue.clear() @contextlib.contextmanager def worker_state(self, state_list, worker_thread): """ 用于记录线程中正在等待的线程数 """ state_list.append(worker_thread) try: yield finally: state_list.remove(worker_thread) # How to use pool = ThreadPool(5) def callback(status, result): # status, execute action status # result, execute action return value pass def action(i): print(i) if __name__ == "__main__": for i in range(30): ret = pool.run(action, (i,), callback) time.sleep(0.01) # 等待的时间xiao'l print(len(pool.generate_list), len(pool.free_list)) print(len(pool.generate_list), len(pool.free_list)) pool.close() # 子线程结束时,主线程就结束,time.sleep后的内容可能没有结果 # pool.terminate()