python创建线程的方法_深入浅出Python多线程(1)创建线程

图片来源于网络

Thread对象

Thread对象位于Python标准库中的threading.py中。

它的初始化方法是这样的:

def __init__(self,group=None,target=None,name=None,

args=(),kwargs=None,*,daemon=None)

一个线程通过调用其start()方法来激活,每个线程对象只能调用一次start(),否则会抛出RuntimeError错误。

假设我们现在有一场跑步比赛,共有5名运动员参加。发令枪一响,大家肯定同时开始跑(并发),直到所有的运动员跑完,比赛结束。在这个例子里面,我们可以把赛场看成是一个进程,而赛场里面的每个运动员占用一条跑道,这个是线程。发令枪一响,所有线程启动,直到运行结束。

让我们模拟一下上述场景,我们可以用两种方式来实现。为了模拟跑步,我们引入一个random来产生一个随机事件,然后使用time.sleep模拟跑步用时,尽量使得结果看起来像那么回事:)

使用函数创建线程

import time

import random

import threading

def runner(name):

time_cost = random.randint(7, 12)

print("{}: 我开始跑了".format(name))

time.sleep(time_cost)

print("{}: 我跑完了,用时{}秒".format(name, time_cost))

if __name__ == '__main__':

# 我们有5个运动员,创建5个线程,分别调用start方法激活线程

name_list = ['张三', '李四', '王五', '赵六', '何二']

for name in name_list:

t = threading.Thread(target=runner, args=(name,))

t.start()

在这个例子中:

我们定义了一个runner函数,来模拟跑步的行为。

我们通过实例化threading.Thread类来创建线程。

在这个例子中,由于runner函数是一个带参数的函数,我们还通过args把参数传给了runner

最后分别调用线程对象的start方法,来开启线程。

# 运行结果

张三: 我开始跑了

李四: 我开始跑了

王五: 我开始跑了

赵六: 我开始跑了

何二: 我开始跑了

李四: 我跑完了,用时7秒

赵六: 我跑完了,用时8秒

何二: 我跑完了,用时8秒

张三: 我跑完了,用时11秒

王五: 我跑完了,用时11秒

我们发现,几乎第一时间,5个人都打印了我开始跑了,最后,李四得了第一名。

通过继承Thread类来创建线程

当然,我们也可以编写面向对象的代码,通过继承Thread类来实现上面的功能。

import time

import random

import threading

class Runner(threading.Thread):

def __init__(self, name):

super().__init__(name=name)

def run(self):

time_cost = random.randint(7, 12)

print("{}: 我开始跑了".format(self.name))

time.sleep(time_cost)

print("{}: 我跑完了,用时{}秒".format(self.name, time_cost))

if __name__ == '__main__':

# 我们有5个运动员,实例化5个Runner对象,分别调用start方法激活线程

name_list = ['张三', '李四', '王五', '赵六', '何二']

for name in name_list:

t = Runner(name)

t.start()

在这个例子中:

我们创建了一个类Runner,让它继承自threading.Thread。

在构造器中我们使用super()来调用父类的构造器,并且把name传给他。

继承Thread来实现多线程最重要的是override父类的run方法,我们把跑步的逻辑放在run方法里面。

最后跟上个例子的逻辑类似,只是我们通过实例化Runner类来创建了线程。

以上就是Python创建线程的两种方式。

两种方式如何选择

继承Thread类的方式虽然可行,但是这样的实现方式是依赖threading库的,代码只能在线程上下文中使用。

而第一种方式,实现的代码可以脱离线程上下文,可以在其他上下文使用。

如果业务逻辑简单,推荐第一种方式(使用函数创建线程)。

如果业务相对复杂,但只跟线程相关,推荐第二种方式(通过继承Thread类来创建线程)。

如果逻辑相对复杂,又不是纯线程业务的,可以实现一个类,还是以实例化Thread类,target传参数的方式去做,比如:

class Runner(object):

def __init__(self, name):

self.name = name

def start(self):

t = threading.Thread(target=self.run)

t.start()

def run(self):

# 线程逻辑

pass

...

节外生枝

在我们上面的例子中,我们很好的实现了模拟赛跑的一个效果。但是别高兴的太早,这时候主办方(产品经理)找过来了,说你程序是跑完了,但是还没有宣布比赛结束,最后你得打印出一行比赛结束才行。

这还不简单,不就是最后加一个打印吗?

...

if __name__ == '__main__':

# 我们有5个运动员,实例化5个Runner对象,分别调用start方法激活线程

name_list = ['张三', '李四', '王五', '赵六', '何二']

for name in name_list:

t = Runner(name)

t.start()

print('比赛结束')

我们来看看结果:

张三: 我开始跑了

李四: 我开始跑了

王五: 我开始跑了

赵六: 我开始跑了

何二: 我开始跑了

比赛结束

王五: 我跑完了,用时8秒

张三: 我跑完了,用时9秒

李四: 我跑完了,用时9秒

何二: 我跑完了,用时9秒

赵六: 我跑完了,用时12秒

WTF,大写的黑人问号,还没跑完就打印啦,这不科学啊。

下一小节,让我们来试着分析并解决这个不同寻常的问题吧。

版权声明

© 著作权归作者所有

允许自由转载,但请保持署名和原文链接。 不允许商业用途、盈利行为及衍生盈利行为。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值