Python的线程Thread的自我介绍

Hello,我是Python里面的线程,今天我就来向大家做个自我介绍吧!

首先,我想说的是,我(线程)不只是在python中会出现,我在任何编程语言中都可以使用代码将我实现,所以,简单来说我是一个机制,在一些特别的情况下会遇到我。

在我自我介绍之前,我先要介绍我的组织——进程( 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.

进程呢,是容纳我的地方,一个进程可以容纳包含许多许多的线程

关于组织(进程)和我(线程)之间的关系如下:

A   在实现了线程的操作系统中,线程是操作系统能够运算调度的最小单位.

(我是最小单位,组织里面有多个我,我是不能被拆分的)

B   线程被包含在进程中,是进程的实际运作单位.

(我隶属于组织,组织是以一个我为单位,由好多很多个我组成的)

C   一个程序的执行实例就是一个进程.

(关于组织其实很好理解,一个组织就是一个完整程序)

介绍完我和进程的关系后,现在我开始来自我介绍啦!

首先要和大家介绍一下我的四个形态:

Ready:就是一开始在准备的状态,一旦我运行了,就在等着被组织调度呢。

Running:这个状态下,我正在被组织派出去执行任务呢。

Blocked:这个时候我就很难受了,由于接收到组织的指令,让我停止当前任务,处于待命状态,进又不是,退又不是,不能动,很难受啊。

Terminated:终结状态,此时的我回到组织休息了,无论我的任务是完成了还是被取消了,我都回到组织准备休假了。

搞清楚这些之后我们就来看看在python中的我是什么样子吧!

在python中,我的名字就是:threading模块

如果想使用我,就需要:

import threading

或者直接引入模块中的方法:

from threading import thread

我们先来看看开发者是怎么定义我的吧:

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

在构造函数中,我包含以下几个参数:

*  target: 线程调用的对象,就是目标函数.(必须要写)

*  name: 为线程起个名字.(必须要写)

args: 为目标函数传递实参, 元组.(有需要传入线程参数的时候才会用)

kwargs: 为目标函数关键字传参, 字典.(同上,只不过是字典类型的)

640?wx_fmt=png

运行结果:

640?wx_fmt=png

通过threading.Thread创建一个线程对象,target是目标函数,name可以指定名称.

但是,仅仅生成线程对象是不行的,我们还需要启动它,这个时候就需要调用start方法,如上图第七行代码所示。

线程会执行函数(def function():.....),是因为线程中就是执行代码的,而最简单的封装就是函数,所以还是函数调用.函数执行完,线程也会随之退出.下面我们看一个一直执行的例子:

640?wx_fmt=png

我们把刚刚的运行函数变成了一个死循环,所以他会一直不停的运行下去。

结果:

640?wx_fmt=png

刚刚在运行第一个例子的时候我们看到了,当run_thread函数运行结束的时候,我们的线程也结束了,所以说,线程结束的标准就是,当它需要执行的东西执行完毕了,它就自然而然的结束了,但是也有例外,如果说,线程执行的函数抛出了异常呢,线程还会继续执行下去吗?

我们来看看例子:

还是将上面的run_thread函数修改一下:

640?wx_fmt=png

看一下运行结果:

640?wx_fmt=png

ok,看了上面的运行结果我们就知道答案是否定的,一旦线程内的方法抛出异常,那么它本身将不会再执行了。所以我们总结一下,一般线程在什么时候会退出:

  • 线程函数内语句执行完毕.

  • 线程函数中抛出未处理的异常.

在python中,线程不具有优先级或线程组的概念,也不能被销毁、停止、挂起,自然也没有恢复、中断。这一点和其他语言是不一样的。

下面我们讲一下线程的属性和方法:

current_thread()  # 返回当前线程对象.

main_thread()  # 返回主线程对象.

active_count()  # 当前处于alive状态的线程个数.

enumerate()  # 返回所有活着的线程的列表

get_ident()  # 返回当前线程ID,非0整数.

start()  # 启动线程。每一个线程必须且只能执行该方法一次。

run()  # 运行线程函数。

写个代码看看他们是什么吧:

640?wx_fmt=png

执行结果:

640?wx_fmt=png

我们现在来看一下run方法是什么方法,怎么现在都没用过?

其实我们已经在用了,我们之前用的start()方法会调用run()方法,run()方法可以运行函数。

640?wx_fmt=png

我们写一个自己的类继承自threading,我们重写了start方法和run方法,并且在里面加了标记,现在我们来跑一下代码:

640?wx_fmt=png

结果打印出来了”调用了run方法“,这就证明了我们刚刚的说法是对的

下面我们看看多线程,多线程是什么呢?当然就是许多许多线程同时在一起工作啦!

很简单,我们可以给刚刚的函数生成多个线程对象不久可以了吗?(是不是很聪明,哈哈哈哈)

640?wx_fmt=png

看输出结果:

640?wx_fmt=png

正好是执行四次(他们的顺序是无序的,我把t1-t4这样写出来是为了证明有四个线程,他们之间运行没有先后,就看谁先抢到资源,谁就先运行了)

当使用start方法启动线程后,进程内有多个活动的线程并行的工作,就是多线程。

一个进程中至少有一个线程,并作为程序的入口,这个线程就是主线程。一个进程至少有一个主线程。其他线程称为工作线程。

在多线程的时候我们经常会用到join方法,join方法是控制一个线程调用另一个线程的方法。join方法有一点是要强调的,就是它是保证当前线程运行完成后再去执行其他线程的。

我们来看一个简单的例子:

首先我们不用join:

640?wx_fmt=png

它会直接把结果一下子就输出来,程序结束,不会一秒一秒的等。

如果我们把join加上,hello world!就会一秒一秒地有序输出,然后结束程序。

join有一个timeout参数:

  1. 当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和。简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。

  2. 没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。

关于线程,我们今天就介绍到这里啦!

听说有气质的人都会关注这个公众号!

640?wx_fmt=jpeg

文章来源: blog.csdn.net,作者:敲代码的灰太狼,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/tongtongjing1765/article/details/100581801

(完)