python多线程编程模块_Python多线程编程(一):threading 模块 Thread 类的用法详解...

转载来自:https://frank909.blog.csdn.net/article/details/85101144

我们进行程序开发的时候,肯定避免不了要处理并发的情况。

一般并发的手段有采用多进程和多线程。

但线程比进程更轻量化,系统开销一般也更低,所以大家更倾向于用多线程的方式处理并发的情况。

Python 提供多线程编程的方式。

本文基于 Python3 讲解,Python 实现多线程编程需要借助于 threading 模块。

所以,我们要在代码中引用它。

import threading

threading 模块中最核心的内容是 Thread 这个类。

我们要创建 Thread 对象,然后让它们运行,每个 Thread 对象代表一个线程,在每个线程中我们可以让程序处理不同的任务,这就是多线程编程。

值得注意的是,程序运行时默认就是在主线程上

创建 Thread 对象有 2 种手段。

直接创建 Thread ,将一个 callable 对象从类的构造器传递进去,这个 callable 就是回调函数,用来处理任务。

编写一个自定义类继承 Thread,然后复写 run() 方法,在 run() 方法中编写任务处理代码,然后创建这个 Thread 的子类。

1. 直接创建 Thread 对象。

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

Thread 的构造方法中,最重要的参数是 target,所以我们需要将一个 callable 对象赋值给它,线程才能正常运行。

如果要让一个 Thread 对象启动,调用它的 start() 方法就好了。

下面是代码示例。

importthreadingimporttimedeftest():for i in range(5):print('test',i)

time.sleep(1)

thread= threading.Thread(target=test)

thread.start()for i in range(5):print('main', i)

time.sleep(1)

上面代码很简单,在主线程上打印 5 次,在一个子线程上打印 5 次。

运行结果如下:

test 0

main 0

main 1

test 1

main 2

test 2

main 3

test 3

main 4

test 4

上面的 callable 没有参数,如果需要传递参数的话,args 是固定参数,kwargs 是可变参数。

Thread 的名字

每一个 Thread 都有一个 name 的属性,代表的就是线程的名字,这个可以在构造方法中赋值。

如果在构造方法中没有个 name 赋值的话,默认就是 “Thread-N” 的形式,N 是数字。

importthreadingimporttimedeftest():for i in range(5):print(threading.current_thread().name+'test',i)

time.sleep(1)

thread= threading.Thread(target=test)

thread.start()for i in range(5):print(threading.current_thread().name+'main', i)

time.sleep(1)

通过 thread.current_thread() 方法可以返回线程本身,然后就可以访问它的 name 属性。

上面代码运行结果如下:

Thread-1 test 0

MainThread main 0

Thread-1 test 1

MainThread main 1

Thread-1 test 2

MainThread main 2

Thread-1 test 3

MainThread main 3

Thread-1 test 4

MainThread main 4

如果我们在 Thread 对象创建时,构造方法里面赋值。

thread = threading.Thread(target=test,name='TestThread')

那么,运行结果会变成这个样子。

TestThread test 0

MainThread main 0

MainThread main 1

TestThread test 1

MainThread main 2

TestThread test 2

MainThread main 3

TestThread test 3

MainThread main 4

TestThread test 4

Thread 的生命周期

创建对象时,代表 Thread 内部被初始化。

调用 start() 方法后,thread 会开始运行。

thread 代码正常运行结束或者是遇到异常,线程会终止。

可以通过 Thread 的 is_alive() 方法查询线程是否还在运行。

值得注意的是,is_alive() 返回 True 的情况是 Thread 对象被正常初始化,start() 方法被调用,然后线程的代码还在正常运行。

importthreadingimporttimedeftest():for i in range(5):print(threading.current_thread().name+'test',i)

time.sleep(0.5)

thread= threading.Thread(target=test,name='TestThread')#thread = threading.Thread(target=test)

thread.start()for i in range(5):print(threading.current_thread().name+'main', i)print(thread.name+'is alive', thread.isAlive())

time.sleep(1)

在上面的代码中,我让 TestThread 比 MainThread 早一点结束,代码运行结果如下。

TestThread test 0

MainThread main 0

TestThread is alive True

TestThread test 1

MainThread main 1

TestThread is alive True

TestThread test 2

TestThread test 3

MainThread main 2

TestThread is alive True

TestThread test 4

MainThread main 3

TestThread is alive False

MainThread main 4

TestThread is alive False

我们可以看到,主线程通过调用 TestThread 的 isAlive() 方法,准确查询到了它的存货状态。

join() 提供线程阻塞手段。

上面代码两个线程是同时运行的,但如果让一个先运行,一个后运行,怎么做呢?

调用一个 Thread 的 join() 方法,可以阻塞自身所在的线程。

importthreadingimporttimedeftest():for i in range(5):print(threading.current_thread().name+'test',i)

time.sleep(0.5)

thread= threading.Thread(target=test,name='TestThread')

thread.start()

thread.join()for i in range(5):print(threading.current_thread().name+'main', i)print(thread.name+'is alive', thread.isAlive())

time.sleep(1)

主线程创建了 TestThread 对象后,让其 start,然后通过调用 join() 方法,实现等待。程序运行结果如下:

TestThread test 0

TestThread test 1

TestThread test 2

TestThread test 3

TestThread test 4

MainThread main 0

TestThread is alive False

MainThread main 1

TestThread is alive False

MainThread main 2

TestThread is alive False

MainThread main 3

TestThread is alive False

MainThread main 4

TestThread is alive False

默认的情况是,join() 会一直等待对应线程的结束,但可以通过参数赋值,等待规定的时间就好了。

def join(self, timeout=None):

timeout 是一个浮点参数,单位是秒。

如果我们更改上面的代码。

thread.join(1.0)

它的结果会是这样。

TestThread test 0

TestThread test 1

MainThread main 0

TestThread is alive True

TestThread test 2

TestThread test 3

MainThread main 1

TestThread is alive True

TestThread test 4

MainThread main 2

TestThread is alive False

MainThread main 3

TestThread is alive False

MainThread main 4

TestThread is alive False

主线程只等待了 1 秒钟。

Thread 中的 daemon 属性

有同学可能会注意到,Thread 的构造方法中有一个 daemon 参数。默认是 None。

那么,daemon 起什么作用呢?

我们先看一段示例代码。

importthreadingimporttimedeftest():for i in range(5):print(threading.current_thread().name+'test',i)

time.sleep(2)

thread= threading.Thread(target=test,name='TestThread')#thread = threading.Thread(target=test,name='TestThread',daemon=True)

thread.start()for i in range(5):print(threading.current_thread().name+'main', i)print(thread.name+'is alive', thread.isAlive())

time.sleep(1)

我们让主线程执行代码的时长比 TestThread 要短。

程序运行结果如下。

TestThread test 0

MainThread main 0

TestThread is alive True

MainThread main 1

TestThread is alive True

TestThread test 1

MainThread main 2

TestThread is alive True

MainThread main 3

TestThread is alive True

TestThread test 2

MainThread main 4

TestThread is alive True

TestThread test 3

TestThread test 4

MainThread 没有代码运行的时候,TestThread 还在运行。

这是因为 MainThread 在等待其他线程的结束。

TestThread 中 daemon 属性默认是 False,这使得 MainThread 需要等待它的结束,自身才结束。

如果要达到,MainThread 结束,子线程也立马结束,怎么做呢?

其实很简单,只需要在子线程调用 start() 方法之前设置 daemon 就好了。

当然也可以在子线程的构造器中传递 daemon 的值为 True。

thread = threading.Thread(target=test,name='TestThread',daemon=True)#thread.setDaemon(True)

更改前面代码示例,运行结果如下

TestThread test 0

MainThread main 0

TestThread is alive True

MainThread main 1

TestThread is alive True

TestThread test 1

MainThread main 2

TestThread is alive True

MainThread main 3

TestThread is alive True

TestThread test 2

MainThread main 4

TestThread is alive True

可以看到 MainThread 结束了 TestThread 也结束了。

2.自定义类继承 Thread

前面讲过,直接初始化一个 Thread,然后,现在还有一种方式就是自定义一个 Thread 的子类,然后复写它的 run() 方法。

importthreadingimporttimeclassTestThread(threading.Thread):def __init__(self,name=None):

threading.Thread.__init__(self,name=name)defrun(self):for i in range(5):print(threading.current_thread().name + 'test', i)

time.sleep(1)

thread= TestThread(name='TestThread')

thread.start()for i in range(5):print(threading.current_thread().name+'main', i)print(thread.name+'is alive', thread.isAlive())

time.sleep(1)

上面的代码,我们自定义了 TestThread 这个类,然后继承了 threading.Thread。

只有在 run() 方法中处理逻辑。最终代码运行结果如下:

TestThread test 0

MainThread main 0

TestThread is alive True

TestThread test 1

MainThread main 1

TestThread is alive True

TestThread test 2

MainThread main 2

TestThread is alive True

MainThread main 3

TestThread is alive True

TestThread test 3

MainThread main 4

TestThread test 4

TestThread is alive True

这与之前的效果并无差异,但我还是推荐用这种方法,毕竟面向对象编程嘛。

自此,Python 多线程编码技术就大致介绍完毕,大家可以进行实际代码编写了。

但是,多线程编程的难点在于多个线程之间共享数据的同步,这是非常容易出错的地方,我将分别编写相应的博文去介绍一些高级的技术点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自动控制节水灌溉技术的高低代表着农业现代化的发展状况,灌溉系统自动化水平较低是制约我国高效农业发展的主要原因。本文就此问题研究了单片机控制的滴灌节水灌溉系统,该系统可对不同土壤的湿度进行监控,并按照作物对土壤湿度的要求进行适时、适量灌水,其核心是单片机和PC机构成的控制部分,主要对土壤湿度与灌水量之间的关系、灌溉控制技术及设备系统的硬件、软件编程各个部分进行了深入的研究。 单片机控制部分采用上下位机的形式。下位机硬件部分选用AT89C51单片机为核心,主要由土壤湿度传感器,信号处理电路,显示电路,输出控制电路,故障报警电路等组成,软件选用汇编语言编程。上位机选用586型以上PC机,通过MAX232芯片实现同下位机的电平转换功能,上下位机之间通过串行通信方式进行数据的双向传输,软件选用VB高级编程语言以建立友好的人机界面。系统主要具有以下功能:可在PC机提供的人机对话界面上设置作物要求的土壤湿度相关参数;单片机可将土壤湿度传感器检测到的土壤湿度模拟量转换成数字量,显示于LED显示器上,同时单片机可采用串行通信方式将此湿度值传输到PC机上;PC机通过其内设程序计算出所需的灌水量和灌水时间,且显示于界面上,并将有关的灌水信息反馈给单片机,若需灌水,则单片机系统启动鸣音报警,发出灌水信号,并经放大驱动设备,开启电磁阀进行倒计时定时灌水,若不需灌水,即PC机上显示的灌水量和灌水时间均为0,系统不进行灌水。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值