1. 线程

from threading import Thread def func(n): print(n) if __name__ == '__main__': t = Thread(target=func, args=(3,)) t.start() print('主线程结束')

from threading import Thread class MyThread(Thread): def run(self): print('XXX') if __name__ == '__main__': t = MyThread() t.start() print('主线程结束')
2. 线程和进程的效率对比
线程的效率非常高, 而且线程的开启不需要消耗资源
import time from threading import Thread from multiprocessing import Process def func(n): num = 0 for n1 in range(n): # 做个运算, 消耗一下时间, 好比较线程与进程的效率 num += n1 print('num', num) if __name__ == '__main__': t_s_t = time.time() # 线程运行起始时间 tlst = [] for i in range(10): t = Thread(target=func, args=(10,)) t.start() tlst.append(t) [t.join() for t in tlst] # 迭代着join等待线程全部运行完毕 t_e_t = time.time() # 线程运行结束时间 t_dif_t = t_e_t - t_s_t # 计算线程的运行时间差 print('线程的结束时间', t_dif_t) p_s_t = time.time() plst = [] for i in range(10): p = Process(target=func, args=(10,)) p.start() plst.append(p) [p.join() for p in plst] p_e_t = time.time() p_dif_time = p_e_t - p_s_t print('进程的结束时间', p_dif_time) print('主线程结束', t_dif_t)
3. 线程之间数据共享

from threading import Thread num = 100 def func(): global num num = 0 if __name__ == '__main__': t = Thread(target=func) t.start() print(num) t.join() print('主线程结束')

import time import random from threading import Thread n = 100 def func(): global n x = n x = x - 1 time.sleep(random.random()) n = x if __name__ == '__main__': for i in range(30): t_lst = [] for i in range(10): t = Thread(target=func) t.start() t_lst.append(t) # [t.join() for t in t_lst] print(n)

import time from threading import Thread, Lock num = 100 def func(t_lock): global num t_lock.acquire() mid = num mid = mid - 1 time.sleep(0.0000001) num = mid t_lock.release() if __name__ == '__main__': t_lock = Lock() t_lst = [] for i in range(10): t = Thread(target=func, args=(t_lock,)) t.start() t_lst.append(t) [t.join() for t in t_lst] print('主线程>>>', num)
4. 锁(同步锁/互斥锁)
1. GIL (Global Interpreter Lock) 全局解释锁
2. Lock 同步锁/互斥锁
3. RLock 递归锁
保证数据安全, 但是牺牲了效率, 同步执行锁内代码
死锁现象: 当我们使用锁嵌套锁时, 多个线程异步执行的时候会出现线程之间相互争夺对方未释放的锁, 相互等待. (互相抢到了对方需要的锁, 导致双方相互等待, 程序没法进行)

import time from threading import Thread, Lock class MyThread(Thread): def __init__(self, lockA, lockB): super().__init__() self.lockA = lockA self.lockB = lockB def run(self): self.f1() self.f2() def f1(self): self.lockA.acquire() print('我拿了A锁') self.lockB.acquire() print('我拿了B锁') print('我是f1') self.lockB.release() self.lockA.release() def f2(self): self.lockB.acquire() time.sleep(1) print('拿到了B锁') self.lockA.acquire() print('拿到了A锁') print('我是f2') self.lockA.release() self.lockB.release() if __name__ == '__main__': lockA = Lock() lockB = Lock() t1 = MyThread(lockA, lockB) t1.start() t2 = MyThread(lockA, lockB) t2.start() print('我是主线程')
解决死锁: 递归锁 RLock 可以多次acquire, 通过一个计数器来记录被锁了多少次, 只有计数器为0的时候, 大家才能继续抢锁.

import time from threading import Thread, Lock, RLock class MyThread(Thread): def __init__(self, lockA, lockB): super().__init__() self.lockA = lockA self.lockB = lockB def run(self): self.f1() self.f2() def f1(self): self.lockA.acquire() print('我拿了A锁') self.lockB.acquire() print('我拿了B锁') print('我是f1') self.lockB.release() self.lockA.release() def f2(self): self.lockB.acquire() time.sleep(1) print('拿到了B锁') self.lockA.acquire() print('拿到了A锁') print('我是f2') self.lockA.release() self.lockB.release() if __name__ == '__main__': lockA = lockB = RLock() t1 = MyThread(lockA, lockB) t1.start() t2 = MyThread(lockA, lockB) t2.start() print('我是主线程')
经典问题: 科学家吃面

import time from threading import Thread,Lock, RLock def eat1(name, lockA, lockB): lockA.acquire() print('%s抢到了叉子' % name) lockB.acquire() print('%s抢到了面条' % name) print('%s开始吃面啦~~' % name) lockB.release() lockA.release() def eat2(name, lockA, lockB): lockB.acquire() print('%s抢到了面条' % name) time.sleep(1) lockA.acquire() print('%s抢到了叉子' % name) print('%s开始吃面啦~~~' % name) lockA.release() lockB.release() if __name__ == '__main__': lockA = lockB = RLock() # lockA = Lock() # lockB = Lock() for name in ['alex', 'wu sir', 'boss king', 'taibai']: t1 = Thread(target=eat1, args=(name, lockA, lockB)) t1.start() t2 = Thread(target=eat2, args=(name, lockA, lockB)) t2.start()
5. 守护线程
主进程代码结束程序并没有结束,并且主进程还存在,进程等待其他的子进程执行结束以后,为子进程收尸,注意一个问题:主进程的代码运行结束守护进程跟着结束,
守护线程:
主线程等待所有非守护线程的结束才结束,主线程的代码运行结束,还要等待非守护线程的执行完毕.这个过程中守护线程还存在

import time from multiprocessing import Process from threading import Thread def func(n): time.sleep(5) print(n) if __name__ == '__main__': # 主线程等待的是子线程的任务全部执行完毕 t = Thread(target=func, args=('我是子线程',)) t.start() # 主进程等待的是给子进程收尸, 回收资源,各种信息 # p = Process(target=func, args=('我是子进程',)) # p.start() print('主线程结束')

import time from multiprocessing import Process from threading import Thread def func1(n): time.sleep(5) print(n) def func2(n): time.sleep(2) print(n) if __name__ == '__main__': # p1 = Process(target=func1, args=('我是1号',)) # p1.daemon = True # p1.start() # p2 = Process(target=func2, args=('我是2号',)) # p2.start() t1 = Thread(target=func1, args=('我是1号',)) # t1.daemon = True t1.start() t2 = Thread(target=func2, args=('我是2号',)) t2.daemon = True # 等待所有非守护线程结束 t2.start() print('主线程结束') # 守护进程在主进程运行代码结束时跟着结束, 不会跟着其他子进程执行
6. 信号量
控制同时能够进入锁内去执行代码的线程数量(进程数量), 维护了一个计数器, 刚开始创建信号量的时候, 假如设置的是4个房间, 进入一次acquire就减1, 出来一个就+1, 如果计数器为0, name其他的任务等待, 这样其他的任务和正在执行的任务是一个同步的状态, 而进入acquire里面去执行的那4个任务是异步执行的.
# 和进程中信号量的按摩房一个道理, 相当于有多把锁 import time from threading import Thread, Semaphore def func1(s): s.acquire() time.sleep(1) print('你好啊') s.release() if __name__ == '__main__': s = Semaphore(4) for i in range(10): t = Thread(target=func1, args=(s,)) t.start()