python-Thread创建线程

概述

本节主要介绍python线程的使用,与对进程的使用类似

线程的生命周期

五种状态:

  • 新建(new): 新创建的线程经过初始化后,进入就绪(Runnable)状态
  • 就绪(Runnable):等待线程调度。调度后进入运行状态
  • 运行(Running):当就绪的线程被调度并获得CPU时,便进入运行状态
  • 阻塞(Blocked):暂停运行,解除阻塞后进入Runnable状态重新等待调度
  • 死亡(Dead):线程方法执行完毕返回或者异常终止

从“运行”进入“阻塞”(Blocked):

  • 同步:线程中获取同步锁,但是资源已经被其他线程锁定时,进入Locked状态,直到该资源可获取(获取的顺序由Lock队列控制)
  • 睡眠:线程运行sleep()或join()方法后,线程进入Sleeping状态。区别在于sleep等待固定的时间,而join是等待子线程执行完。当然join也可以指定一个“超时时间”。从语义上来说,如果两个线程a,b, 在a中调用b.join(),相当于合并(join)成一个线程。最常见的情况是在主线程中join所有的子线程。
  • 等待:线程中执行wait()方法后,线程进入Waiting状态,等待其他线程的通知(notify)。

感性认识

普通方式:

import os

while True:
    print('pid=%d'%os.getpid())

执行结果:

查看该进程的线程数量:

只有一个主线程

多线程方式:

先实现一个最简单的多线程程序,运行查看结果

#coding=utf-8

from threading import Thread
import time
import os

def task1():
    #任务1
    while True:
        print('1')
        time.sleep(1)

def task2():
    #任务2
    while True:
        print('2')
        time.sleep(1)

print('pid=%d'%os.getpid())
#创建2个线程,与Process类似
t=Thread(target=task1)
t2=Thread(target=task2)
#启动线程
t.start()
t2.start()
print('代码结束')

执行结果:

查看该进程的线程数量:

该进程有3个线程,1个主线程,2个由主线程创建的子线程

python多线程与多进程的区别

  • 只有一个进程,该进程的线程数有多个
  • 不需要重新读取py文件,只是调用函数

Thread类使用说明

导入模块

import threading

或者

from threading import Thread

创建对象

语法:

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

参数说明:

  • group:一般不使用
  • target:表示调用对象
  • name:为别名
  • args:表示调用对象的位置参数元组
  • kwargs:表示调用对象的关键字参数字典

常用属性

  • name:当前线程别名,在实例化时通过参数name指定,默认为Thread=N,N为从1开始递增的整数

常用方法

  • start():启动线程实例

  • is_alive():判断线程实例是否还在执行,返回布尔值

  • join([timeout]):参见

  • run():参见 python-Thread子类创建进程

threading模块使用说明

  • threading.current_thread():返回当前线程对象
  • threading.main_thread():返回主线程对象
  • threading.enumerate():返回当前存在的所有线程对象的列表
  • threading.active_count(): 返回当前存活的线程对象的数量。通过计算len(threading.enumerate())长度而来

Thread创建线程

#coding=utf-8

from threading import Thread,current_thread,active_count,main_thread
import time,os


def task():
    ct=current_thread()
    mt=main_thread()
    print('task()---子线程开始----当前线程名称:%s,主线程名称:%s'%(ct.name,mt.name))
    time.sleep(1)
    # time.sleep(4)
    print('task()---子线程结束----当前线程名称:%s,主线程名称:%s'%(ct.name,mt.name))

if __name__ == "__main__":
    print('pid=%s'%os.getpid())
    t=Thread(target=task,name='子线程')
    t.start()

    print('main()---主线程名称:%s'%current_thread().name)
    print('main()---线程活动总数:%d'%active_count())
    time.sleep(3)
    print('main()---线程活动总数:%d'%active_count())
    print('最后一行代码')

执行结果:

pid=6804
task()---子线程开始----当前线程名称:子线程,主线程名称:MainThread
main()---主线程名称:MainThread
main()---线程活动总数:2
task()---子线程结束----当前线程名称:子线程,主线程名称:MainThread
main()---线程活动总数:1
最后一行代码
结论:

创建并启动子线程后,主线程仍然继续执行

注释掉11行代码,释放12行代码

执行结果如下:

pid=9152
task()---子线程开始----当前线程名称:子线程,主线程名称:MainThread
main()---主线程名称:MainThread
main()---线程活动总数:2
main()---线程活动总数:2
最后一行代码
task()---子线程结束----当前线程名称:子线程,主线程名称:MainThread
结论:

子线程运行结束后,进程才会结束

守护线程

def task():
    print('子线程-启动')
    time.sleep(1)
    print('子线程-结束')

def task2():
    print('守护线程-启动')
    time.sleep(3)
    print('守护线程-结束')

if __name__ == "__main__":
    print('pid=%s'%os.getpid())
    t=Thread(target=task)
    t2=Thread(target=task2,daemon=True)
    t.start()
    t2.start()
    print('最后一行代码')

结果:

pid=8208
子线程-启动
守护线程-启动
最后一行代码
子线程-结束
结论:

当只剩下守护线程时,进程结束


原文出处:/show_1EF2piZVIM5F.html