22 并发编程02
线程
线程指的是在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。
一、进程与线程的区别
进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。]
主进程中的线程称为主线程,其他开启的线程称为子线程开进程的开销远远大于开线程
同一进程内的多个线程共享该进程的地址空间
from multiprocessing import Process p1=Process(target=task,) 换成 from threading import Thread t1=Thread(target=task,)
计算密集型的多线程下不能增强性能,多进程才可以,,I/O密集型的多线程会加快程序的执行速度
二、threading模块介绍
multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性
1、Thread实例对象的方法
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。
2、threading模块提供的一些方法:
threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
""" 进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。] 主进程中的线程称为主线程,其他开启的线程称为子线程 """ # 如何开启线程 from multiprocessing import Process from threading import Thread def task(): print("子线程") if __name__ == '__main__': t = Thread(target=task) t.start() print("主线程")二、GIL全局解释器锁
""" Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行 虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。 由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。 1. python代码在解释器中执行,cpython解释器, pypy解释器 2. GIL锁在解释器中存在,他只在cpython解释器中,pypy解释器中不存在 3. 起一个垃圾回收线程,起一个正常执行的线程,垃圾回收还没回收完毕,另一个线程可能会抢占资源 4. 设置了一把全局解释器锁(GIL锁),有了这把锁,就保证同一时刻,只能有一个线程执行, 只要线程想执行,那么,就必须拿到这把GIL锁 5. 如果是io密集型:选择线程 6. 如果是计算密集型:选择进程 """ # print(123) # import sys # print(sys.argv) # print(sys.argv[0]) # print(sys.argv[1]) # print(sys.argv[2]) # print(sys.argv[3]) # # time = '2021-09'三、进程与线程的区别
from multiprocessing import Process from threading import Thread import time # def task(): # time.sleep(1) # print(123) # # # if __name__ == '__main__': # ctime = time.time() # p = Process(target=task) # p.start() # p.join() # print(time.time() - ctime) # def task(): # time.sleep(1) # print(123) # # # if __name__ == '__main__': # ctime = time.time() # p = Thread(target=task) # p.start() # p.join() # print(time.time() - ctime) def work(): global n n=0 if __name__ == '__main__': # n=100 # p=Process(target=work) # p.start() # p.join() # print('主',n) # 毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100 n=1 t=Thread(target=work) t.start() t.join() print('主',n) # 查看结果为0,因为同一进程内的线程之间共享进程内的数据四、Thread类的其他方法
from threading import Thread import threading import time def work(): time.sleep(1) global n n = 0 # print(threading.currentThread()) if __name__ == '__main__': t = Thread(target=work) t.start() # print(t.isAlive()) # print(t.is_alive()) # getName():返回线程名。 # print(t.getName()) # setName():设置线程名 # t.setName('ly_1') # print(t.getName()) # print(threading.currentThread()) # 返回当前的线程变量。 print(threading.enumerate())五、守护线程
from threading import Thread import time def sayhi(name): time.sleep(2) print('%s say hello' % name) if __name__ == '__main__': t = Thread(target=sayhi, args=('nick',)) t.setDaemon(True) # 必须在t.start()之前设置 t.start() print('主线程') print(t.is_alive()) ''' 主线程 True '''六、互斥锁(同步锁)
from threading import Thread,Lock import time def task(lock): global n lock.acquire() temp = n time.sleep(1) n = temp - 1 # n -= 1 lock.release() if __name__ == '__main__': n = 10 l = [] lock = Lock() for i in range(10): t = Thread(target=task, args=(lock, ) ) t.start() l.append(t) for j in l: j.join() print(n)七、信号量
from threading import Thread, Semaphore from multiprocessing import Process, Lock # Semaphore:信号量可以理解为多把锁,同时允许多个线程来更改数据 import time, random sm = Semaphore(2) def task(i): sm.acquire() print("线程:%s,进来了" % i) time.sleep(random.randint(1, 3)) print("线程:%s,出去了" % i) sm.release() if __name__ == '__main__': for i in range(6): t = Thread(target=task, args=(i,)) t.start()八、Event事件
from threading import Thread, Event import time def girl(event): print("某女正在恋爱中。。。") time.sleep(3) event.set() # 发出信号 print("某女分手了") def boy(i, event): print("屌丝:%s,正在等待某女分手..." % i) event.wait() # 正在等待 print("屌丝:%s,开始追了..." % i) if __name__ == '__main__': event = Event() t = Thread(target=girl, args=(event,)) t.start() for i in range(10): t1 = Thread(target=boy, args=(i, event)) t1.start()