线程
线程是操作系统中能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位
一个线程指的是一个进程中单一顺序的控制流
一个进程可以开启多条线程,多个线程可以并发执行多个任务
注意
1.进程不是一个执行单位,进程是一个资源单位
2.每个进程自带一个线程,线程才是CPU上的执行单位
3.python无法利用多核优势,意味着一个进程下的多个线程无法实现并行
进程 vs 线程
1.进程之间的内存空间彼此隔离,而一个进程下的多个线程共享这个进程的资源
2.创建进程的开销远大于线程,直观来看,创建线程的速度远快于创建进程(百倍级)
1. Threads share the address space of the process that created it; processes have their own address space. 2. Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process. 3. Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes. New threads are easily created; new processes require duplication of the parent process. 4. Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes. 5. Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
一个比喻
可以将进程比喻为各个城市的公交车公司,而线程就是这个公交车公司中的各路公交,一个公交车公司至少要有一条线路的公交车(也就是一个进程至少要拥有一个线程,即我们创建进程时自带的那个线程),而一个公交车公司下所有公交车是可以共享这个公司的资源的(一个进程下的多个线程可以共享这个进程的资源),而这个城市的公交车公司资源是不能与另外一个城市的公交车公司共享的(进程的内存空间是彼此隔离的,且是物理层面隔离的),此外,创建一个公司显然比直接在这个公司内开一条公交线路开销大(创建进程的开销远大于创建线程)
开启线程的方式
和开启进程的方式大同小异
方式一
import time from threading import Thread def task(name): print('%s is running' % name) time.sleep(3) print('%s is done' % name) t = Thread(target=task,args=('线程',)) t.start() print('主')
方式二
class MyThread(Thread): def run(self): print('%s is running' % self.name) time.sleep(3) print('%s is done' % self.name) t = MyThread() # 执行t.start() 实际上是在属性查找,找到Thread类中的start方法,而start方法内有self.run() t.start() print('主') # 运行结果 Thread-1 is running 主 Thread-1 is done
从运行结果来看,可以发现以下几点
1.开启线程的速度块。和进程一样,start()操作实际上是向操作系统发送请求,由操作系统创建,而线程几乎是在发送请求的瞬间被创建
2.在这个进程下,拥有两个线程(一个是创建进程时自带的那个线程)
3.print(主)的执行代表着自带那个线程的代码执行结束,而当我们只有这个线程时,主进程的代码结束其实就是这个线程的结束,主进程会等待所有子进程结束后发送请求,回收pid,并真正结束,而此时,自带那个线程的结束,并没有引起主进程的结束,这意味着自带那个线程的结束是要等到所有其它线程的结束而真正结束
此外,线程之间并没有父子关系
线程的其他方法
Thread实例对象的方法 # isAlive(): 返回线程是否活动的。 # getName(): 返回线程名。 # setName(): 设置线程名。 threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程变量。 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。