一、多线程基础
进程拥有资源(内存等),线程不拥有资源,共享进程的资源
同属于一个进程中的线程可以共享CPU分配的全部资源
多个线程的切换速度比多个进程快,消耗的资源也少。
多个线程可以并行地在多核CPU中执行。
进程是系统资源分配的基本单元
线程是CPU 调度和分配的基本单位
线程不拥有系统资源,但可以访问隶属于进程的资源
一个进程默认有一个线程
线程是由操作系统调用的
协程是由用户调用的
""" 线程类:threading.Thread 线程任务:target 线程任务的参数:args 线程名:name
该举例1个进程,2个线程 """ import threading import time def music(user): for i in range(5): time.sleep(1) print(f'{user}正在听音乐{i}') print(f'{threading.current_thread().name}正在运行') def lol(user): for i in range(5): time.sleep(1) print(f'{user}正在玩LOL{i}') print(f'{threading.current_thread().name}正在运行') def main(): # 创建2个线程 t1 = threading.Thread(target=music, args=('小样儿',), name='线程1') t2 = threading.Thread(target=lol, kwargs={'user': '小样儿'}, name='线程2') # 启动线程 t1.start() t2.start() t1.join() # 阻塞 t2.join() print("程序结束!") if __name__ == '__main__': main()
二、多线程共享全局变量
import threading n = 100 def work1(): global n for i in range(1000): n += 1 def work2(): global n for i in range(1000): n += 1 if __name__ == '__main__': t1 = threading.Thread(target=work1) t2 = threading.Thread(target=work2) t1.start() t2.start() t1.join() t2.join() print(f'n:{n}') # 2100
三、线程锁
根据以上例子,当线程并发次数多时,如range(100000)等,就会出错
因此需要线程锁,确保每次
import threading n = 200000 lock = threading.Lock() def work(): global n for i in range(100000): lock.acquire() # 关门上锁 # with lock: # 防止同时修改n n -= 1 lock.release() # 解锁 if __name__ == '__main__': t1 = threading.Thread(target=work) t2 = threading.Thread(target=work) t1.start() t2.start() t1.join() t2.join() print(f'n:{n}')
四、自定义线程类
import threading import time class MyThread(threading.Thread): def __init__(self, user): super(MyThread, self).__init__() self.user = user def run(self): """线程启动的时候会调用此方法""" for i in range(5): time.sleep(1) print(f'{self.user}正在听音乐...') if __name__ == '__main__': t = MyThread(user='小样儿') t.start()
五、线程池
import time from concurrent.futures import ThreadPoolExecutor def work(result): time.sleep(1) print("Hello!") return result def main(): thread_executor = ThreadPoolExecutor(max_workers=5) future = thread_executor.submit(work, "完成") print(future.done()) time.sleep(2) print(future.done()) print(future.result()) if __name__ == '__main__': main() ''' False Hello! True 完成 '''
参考资料转自:https://www.cnblogs.com/hoojjack/p/10846010.html
六、第三方线程池(threadpool)
安装:pip install threadpool
import time import threadpool def hi(s): print(f"hi,{s} ") time.sleep(2) def main(): start_time = time.time() thread_pool = threadpool.ThreadPool(2) reqs = threadpool.makeRequests(hi, ['a', 'b', 'c']) for req in reqs: thread_pool.putRequest(req) thread_pool.wait() # 等待线程池中的所有线程执行完毕 end_time = time.time() print(f'总共花费时间为:{end_time - start_time}') if __name__ == '__main__': main() ''' hi,a hi,b hi,c 总共花费时间为:4.006930828094482 '''
七、GIL锁
GIL: 中文全局“解释器”锁。锁的是谁利用CPU,锁不住代码
线程占用CPU: 无论是多核CPU,还是多CPU,同一间时间,只有一个线程在使用CPU
CPU密集型场景,不要用多线程,用了反而慢,原因是Python不能利用多核(GIL决定的)
IO密集型场景,使用多线程可以节省时间。因为IO不占用CPU,GIL锁影响不大。