并发编程之线程
多进程
核心--多道技术
切换+保存状态
程序I/O操作较多时,可提高程序效率
概念:线程是应用程序中工作的最小单元,或者又称之为微进程。
进程是一个资源单位,包含运行程序所需的所有资源,线程才是CPU上的执行单位
每个进程一旦被创建,就默认开启了一条线程,其为主线程,有且只有一个。
执行代码时,如遇I/O系统会自动切换到其他应用程序--降低了当前应用程序的效率。若进程中不仅有主线还有其他线程,主线遇到I/O时--切到其他线程,保证了应用程序对CPU利用率(占用率)
对于CPU而言,只有线程可以被执行,所以CPU切换是在不同线程之间进行切换,开启多线程可提高效率---
多线程即在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间
创建进程的开销要远大于线程
进程之间是竞争关系,线程之间是协作关系
使用线程:提高效率
为何不用多进程--进程对操作系统的资源耗费非常高
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。
- 线程可以被抢占(中断)。
- 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让。
线程可以分为:
- 内核线程:由操作系统内核创建和撤销。
- 用户线程:不需要内核支持而在用户程序中实现的线程。
使用:
- threading(推荐使用)
thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 "_thread"。反正你不要再用就是了! 我习惯上用 from threading import Thread
两种开启线程的方式
1.实例化Thread
2.继承Thread类,覆盖run方法
# 开启进程第一种方式 from threading import Thread def task(): print("threading running") t1=Thread(target=task) t1.start() print("over") # 第二种方式 class MyThread(Thread): def run(self): print("子线程 running...") MyThrestart() print("over2")
当程序中遇到I/O时-------开启多线程,当程序中为纯计算任务时-----无法提高效率
多线程与多进程区别:
1.多个线程共享创建它的进程的地址空间,资源共享;进程有自己的地址空间。 2.线程可以直接访问其进程的数据段;进程有它们自己的父进程数据段的副本。 3.线程可以直接与其进程的其他线程通信;进程必须使用进程间通信来与同级进程通信。 4.新线程很容易创建;新进程需要重复父进程。 5.线程可以对同一进程的线程进行相当大的控制;进程只能对子进程进行控制。 6.对主线程的更改(取消、优先级更改等)可能会影响进程的其他线程的行为;对父进程的更改不会影响子进程。
进程对操作系统的资源耗费非常高,线程非常低
进程数据相互隔离,同一进程中线程数据共享
IO密集的程序 ---多线程---IO反正都要被阻塞,切换 线程的方式不会比进程慢多少
计算密集的程序 ---多进程 ---利用多核可以达到并行!
# 开启进程第一种方式 from threading import Thread def task(): print("threading running") t1=Thread(target=task) t1.start() print("over") # 对比进程启动时间 from multiprocessing import Process def task(): print("running") if __name__ == '__main__': t2=Process(target=task) t2.start() print("over...")
守护线程(setDaemon)
在(同进程下)所有非守护线程结束后结束
守护进程使用--生产者消费者模型
one) if __name__ == '__main__': q = JoinableQueue() #生产者1 c1 = Process(target=make_hotdog,args=("万达热狗店",q)) c1.start() #生产者2 c2 = Process(target=make_hotdog, args=("老男孩热狗店", q)) c2.start() # 消费者 p2 = Process(target=eat_hotdog,args=("思聪",q)) p2.start() # 首先保证生产者全部产完成 c1.join() c2.join() # 保证队列中的数据全部被处理了 q.join() # 明确生产方已经不会再生成数据了
threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法: threading.currentThread(): 返回当前的线程变量。 threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。 除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法: run(): 用以表示线程活动的方法。 start():启动线程活动。 join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。 setDaemon(True):守护主线程,跟随主线程退(必须要放在start()上方) isAlive(): 返回线程是否活动的。 getName(): 返回线程名。 setName(): 设置线程名。