线程:进程中的每一个子任务,不能独立存在
进程:独立的所有子任务的集合
线程,进程:目的都是想同时完成任务
一。什么是进程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
系统资源:线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
进程的作用和定义:进程是为了提高CPU的执行效率,减少因为程序等待带来的CPU空转以及其他计算机软硬件资源的浪费而提出来的。进程是为了完成用户任务所需要的程序的一次执行过程和为其分配资源的一个基本单位,是一个具有独立功能的程序段对某个数据集的一次执行活动。
二。线程和进程的区别:
1、线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。
2、一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
3、系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,除了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
4、与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。
5、进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。
三。线程相对进程的优点
进程切换比线程切换开销大是因为进程切换时要切页表,而且往往伴随着页调度,因为进程的数据段代码段要换出去,以便把将要执行的进程的内容换进来。本来进程的内容就是线程的超集。而且线程只需要保存线程的上下文(相关寄存器状态和栈的信息)就了,动作很小。
四。进程与程序的区别:
程序是一组指令的集合,它是静态的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般说来,一个进程肯定与一个程序相对应,并且只有一个,但是一个程序可以有多个进程,或者一个进程都没有也可以只有一个进程。除此之外,进程还有并发性和交往性。简单地说,进程是程序的一部分,程序运行的时候会产生进程。总结:线程是进程的一部分,进程是程序的一部分。
Thread:表示一个线程的执行的对象
Lock: 锁 原语对象(跟thread模块里的锁对象相同)
生成Lock对象后的方法: acquire() 得到锁 . release()释放锁
RLock:可重入锁对象.使单线程可以再次获得已经获得了的锁(递归锁定).
Condition:条件变量对象能让一个线程停下来.等待其它线程满足了某个”条件”.如状态的改变或者值的改变.
Event:通用的条件变量.多个线程可以等待某个事件的发生,在事件发生后,所有的线程都会被激活.
Semaphore :为等待锁的线程提供一个类似”等候厅”的结构
BoundedSemaphore与Semaphore类似,只是它不允许超过初始值
Timer与Thread相似,只是它要等待一段时间后才开始运行.
activeCount():当前活动的线程对象的数量
currentThread():返回当前线程对象
enumerate(): 返回当前活动线程列表
settrace(func):为所有线程设置一个跟踪函数
setprofile(func):为所有线程设置一个profile函数
import threading,time
class MyThread(threading.Thread):
def __init__(self,name=None):
threading.Thread.__init__(self)
self.name=name
print("__mian__")
def run(self):
for i in range(10):
if i==3:
print(self.name,i)
time.sleep(1)
def start(self):
print("start")
super().start()
lock=threading.Lock()
coin=threading.Thread(lock=lock)
t=MyThread("线程1")
t.start()
for i in range(20,10,-1):
print("主线程",i)
time.sleep(1)
生成对象后可以使用的方法:
start():开始线程的执行
run(): 定义线程的功能的函数(一般会被子类重写)
join(timeout=None):程序挂起,直到线程结束;如果给了timeout,则最多阻塞timeout秒
getName():返回线程的名字
setName(name):设置线程的名字
isAlive():布尔标志,表示这个线程是否还在运行中
isDaemon()<守护线程>:返回线程daemon的标志
注:如果一个线程不支持守护线程.当主线程退出时,所有的子线程不论它们是否还在工作,都会被强行退出,有时我们并不期望这种行为,这时,就引入了守护线程的概念threading模块支持守护线程.它们就是这样工作的:守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求,它就在那等着.如果你设定一个线程为守护线程,就表示你在说这个线程是不重要的,在进程退出的时候,不用等待这个线程退出.就像你在网络编程看到的,服务器线程运行在一个无限循环中,一般不会退出.
如果你的主线程要退出的时候,不用等待那些子线程完成,那就是设定这些线程的 daemon属性.即,在线程开始(调用thread.start())之前,setDaemon()函数设定线程的daemon标志(thread.setDaemon(True))就表示这个线程”不重要”如果你想要等待子线程完成再退出,那就什么都不用做,或者显式地调用thread.setDaemo(False)以保证其daemon标志为False.
setDaemon(daemonic):把线程的daemon标志设为daemonic(一定要在调用start()函数前调用)
线程的状态:
1.新建状态(New):
当用new操作符创建一个线程时,例如newThread(r),线程还没有开始运行,此时线程处在新建状态。当一个线程处于新生状态时,程序还没有开始运行线程中的代码
2.就绪状态(Runnable)
一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。
3.运行状态(Running)
当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.
4. 阻塞状态(Blocked)
线程运行过程中,可能由于各种原因进入阻塞状态:
1 线程通过调用sleep方法进入睡眠状态;
2 线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
3 线程试图得到一个锁,而该锁正被其他线程持有;
4 线程在等待某个触发条件;
......
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
5. 死亡状态(Dead)
有两个原因会导致线程死亡:
1) run方法正常退出而自然死亡,
2) 一个未捕获的异常终止了run方法而使线程猝死。
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的,或者线程死亡了,则返回false.