python 多线程(一)

2019-01-31  本文已影响0人  原来不语

(一) 线程概述

几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含多个顺序执流,每个顺序执行流就是一个线程。

进程和线程

所有运行中的任务通常对应一个进程(Process)。当一个程序进入内存运行时,即变成一个进程。进程是处于运行过程中的程序,并且具有一定的独立功能。进程是系统进行资源分配调度的一个独立单位。

注意:并发和并行是两个概念,并行指在同一时刻有多条指令在多个处理器上同时执行;并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果。对于CPU在某个时间上只能执行一个程序,也就是运行一个进程,CPU不断地在这些进程之间轮换执行。但是相对于人的感觉CPU执行的速度太快了,所以在CPU虽然在不断的切换,但是用户感觉到好像有多个进程在同时执行。

现代的操作系统都支持多进程的并发执行,但在具体的实现细节上可能因为硬件和操作系统的不同而采取不同的策略,常用的有共享式的多任务操作策略,抢占式的多任务操作策略(效率较高)。
多线程扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务。线程也被称为轻量级进程,线程是进程的执行单元。线程在程序中是独立的、并发的执行流。当进程被初始化后,主线程就被创建了。对于大多数程序而言,通常仅需要一个主线程,但也可以在进程内创建多个顺序执行流,这些顺序执行流就是线程,每个线程都是独立的。 线程是进程的组成部分。

一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源。

线程可以完成一定的任务,可以与其他线程共享父进程中的共享变量及部分环境,相互之间协同完成进程所要完成的任务。线程的运行是抢占式的,也就是说当前运行的线程在任何时候后可能被挂起,以便另外一个线程可以运行,一个线程可以创建和撤销另外一个线程,同一个进程中的多个线程可以并发运行。

操作系统可以同时执行多个任务,每一个任务就是一个进程;进程可以同时执行多个任务,每一个任务就是一个线程。

(二) 多线程的优势

线程在程序中是独立的,并发的执行流,而且线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高程序的运行效率。
线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性,多个线程共享同一个进程的虚拟空间。线程共享的环境包括(进程代码段、进程的共有数据等)利用这些数据,线程之间可以很容易实现通信。操作系统在创建进程时,必须为该进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此使用多线程来实现并发比使用多进程的性能要高的多。

(三)线程的调度和启动

python 中一个线程对应c语言中一个线程
gil使得同一个时刻只有一个线程运行在cpu上执行字节码,无法将多个线程映射到多个cpu上执行
gil会根据执行的字节码行数以及时间释放gil,在遇到io操作时会主动释放
python提供了_thread 和threading 两个模块来支持多线程,其中_thread提供低级别的,原始的线程支持,以及一个简单的锁,但是一般不建议使用_thread模块;而threading模块则提供了功能丰富的多线程支持。
python 主要提供两种方式来创建线程:

调用Thread类的构造器创建线程

调用Thread类的构造器创建线程,直接调用threading.Thread类的如下构造器创建线程。

__init__(self, group= None, target=None, name= None, args=(), kwargs= None, *, daemon= None)

target :指定该线程要调度的目标方法。只传函数名,不传函数,即不加()
args :指定一个元组,以位置参数的形式为target指定的函数传入参数。元组的第一个参数传给target的第一个,以此类推。
kwargs:指定一个字典,以关键字参数的形式为target指定的函数传入参数
daemon: 指定所构建的线程是否为后台线程。

调用Thread类的构造器创建并启动多线程的步骤:

image.png

可以看到在循环变量达到20时,创建并且启动了两个新线程。所以此时一共有三个线程,但是三个线程之间的执行没有没有先后顺序,他们的执行方式为Thread-1执行一段时间Thread-2或MainThread获得CPU执行一段时间。

继承Thread类创建线程类

image.png
class FKThread(threading.Thread):
def __init__(self):
    threading.Thread.__init__(self)
    self.i = 0
#重写run方法

def run(self):
    while self.i < 100:
        #调用threading模块的current_thread()函数获取当前线程
        #调用线程对象的getName()方法获取当前线程的名字
        print(threading.current_thread().getName() + " " + str(self.i))
        self.i += 1


for i in range(100):
print(threading.current_thread().getName() + " " + str(i))
if i == 20:
    #创建并且启动第一个线程
    ft = FKThread()
    ft.start()

    ft2 = FKThread()
    ft2.start()
print("主线程执行完成")
image.png

线程的生命周期

线程被创建以后不是直接就进入执行状态,也不是一直处于执行状态,在线程的生命周期中,他要经历新建、就绪、运行、阻塞和死亡5种状态。

新建和就绪状态

上一篇 下一篇

猜你喜欢

热点阅读