线程:线程是进程中的每个子任务,不能独立存在
进程:独立的所有子任务的集合
线程、进程:目的都是想同时完成任务
进程的特点:独立(内存独立,CPU使用独立)启动进程开销大(速率低),进程之间很难共享数据,和数据通信,数据安全高。
线程的特点:依赖进程(内存共享,cup独立使用),线程之间共享数据容易,方便通信,线程不安全
线程又可以分为:
内核线程:由操作系统内核创建和撤销
用户线程:不需要内核支持而在用户程序中实现的线程
线程常用的两个模块:_thread和threading
Threading 模块除了包括_thread模块中的所有方法外,还提供了其它方法:
threading.currentThread():返回当前的线程变量
threading.enumerate():返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount():返回正在运行的线程数量,与len(threading.currentThread())有相同的结果
除了使用方法外,线程模块同样提供了Thread类来处理线程,
Thread类提供了以下方法:
run():用以表示线程活动的方法
start():启动线程活动
join([time]):等待至线程终止。这阻塞调用线程直至线程的jion()方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
isAlive():返回线程是否是活动的。
getName():返回线程名
setName():设置线程名
python 线程有两种方式:函数方式和类方式:
函数式:
在python3中thread模块以被弃用,为了兼容,在python3中重命名为‘_thread’,threading模块包括了_thread模块的全部功能。
定义新线程: threading.start_thread(function,args[, kwargs])
单线程列子:
import _thread import threading import time def test(): for i in range(1,10): print(i) time.sleep(1) print('------main-------') # 启动线程 threading._start_new_thread(test,()) # 不结束线程 input()
导入模块,定义一个函数,然后定义一个线程,将test函数传入,然后test函数就变成了一个线程,input的作用是等待用户输入,让程序不结束。
多线程例子:
import _thread import threading import time def test(): for i in range(1,10): print(i) time.sleep(1) print('------main-------') # 启动线程 threading._start_new_thread(test,()) for i in range(50,39,-1): print(i) time.sleep(1) # 不结束线程 input()多线程和单线程差不多,单线程只是运行一个线程,多线程是运行多个线程,这里可以不用定义两个线程,只要将一个for语句写在定义新线程前面即可,这也算一个线程。多线程运行的规则:假设有两个线程A和B,多线程运行就是先执行一段A,再执行一段B,这样做的好处可以节省资源和时间。类方式:
单线程:
import _thread import threading import time class mythread(threading.Thread): def __init__(self): threading.Thread.__init__(self) print('mythread') def run(self): for i in range(11): print(i) time.sleep(1) t=mythread() t.start()类方式创建类时要继承threading.Thread这个类,这个类里面有很多方法,其中就有start和run方法,父类也有start方法,我们可以自己不用定义,start方法会自动调用run方法,父类里面也有run方法,我们这里要重写父类的方法。多线程:
import _thread import threading import time class mythread(threading.Thread): def __init__(self,name): threading.Thread.__init__(self) self.name=name print('mythread') def run(self): for i in range(11): print('%s\t%d'%(self.name,i)) time.sleep(1) M1=mythread('mythread_1') M2=mythread('mythread_2') # 线程名字 # t.getName() # print(t) # 继承了父类的start方法,会自动调用run()方法,可以重写,但会失去其中的意义 M1.start() M2.start() for j in range(50,39,-1): print(j) time.sleep(1)这里多线程就要定义两个对象,这就是两个线程,启用后输出的结果是M1和M2分别输出一个数,直至输完。死锁:什么是死锁:
在编写多线程的时候,必须要注意资源的使用问题,如果两个或多个线程分别拥有不同的资源,而又同时需要对方释放资源才能运行,就会发生死锁
简单来说:死锁就是当一个或多个进程都在等待系统资源,而资源本身又被占用时,所产生的一种状态。
造成死锁的原因:多线程竞争共享资源。由于资源被占用,资源不足或进程推进顺序不当等原因造成线程处于永久阻塞状态,从而引发死锁。
这个时候我们就引进了线程锁:
列:
import _thread import threading import time class mythread(threading.Thread): def run(self): for i in range(1,11): # 关锁 cond.acquire() print(i) # 开锁 cond.release() lock=threading.Lock() cond=threading.Condition(lock=lock) M1=mythread() M2=mythread() M1.start() M2.start()结果是M1先输出,M2后输出,这就相当于单线程,一个线程先运行完毕后再运行下一个线程,但线程锁不止这点,它可以根据要求来进行锁,比如M1输出到6的时候就锁住,然后运行M2,M2运行完毕后再运行M1。锁定是单线程运行
线程的状态:
1. 新建状态(New):新创建了一个线程对象
2. 就绪状态(Runnable):线程对象创建后,其它线程调用了该对象的start方法,可运行线程池中,变得可运行,等待获取CPU的使用权
3. 运行状态(Running):就绪状态的线程获取了CPU,暂时停止运行执行程序代码。
4. 阻塞状态(Blocked):阻塞状态是线程因为某些原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞分三种:
1. 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中
2. 同步阻塞:运行的线程在获取对象的同步锁时若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
3. 其它阻塞:运行的线程执行sleep()或join方法,或者发出了I/O时,JVM会把该线程置 阻塞状态。当sleep()状态超时时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态
5.死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命
由于并发的问题,需要加锁:
锁当然有锁定和未锁定两种状态,当一个线程要访问共享数据时,必须要先获得锁定,如果已经有别的线程获得锁,那么就进入暂定状态,等别的线程把锁释放后,再进行操作。
Condition:更精确的控制锁,提供了四个方法,上锁(acquire()),
等待(wait()),解锁(release()),唤醒(notify(),notify_all())
lock=threading.lock()
threading.Condition(lock=lock)