Python学习笔记:线程的创建
python主要是通过thread和threading这两个模块来实现多线程支持。python的thread模块是比较底层的模块,python的threading模块是对thread做了一些封装,可以更加方便的被使用。但是python(cpython)由于GIL的存在无法使用threading充分利用CPU资源,如果想充分发挥多核CPU的计算能力需要使用multiprocessing模块。
一、创建线程
1、_thread.start_new_thread()
python3.x中已经摒弃了Python2.x中采用函数式thread模块中的start_new_thread()函数来产生新线程方式。所以这种方法并不常用。
下面我们来以main方法为主线程,通过_thread模块来创建线程:
import _thread
import threading
import time
def method(arg):
#获取线程的名称
threadName = threading.current_thread().getName()
print(arg)
for i in range(10):
print('我是子线程(%d)@%s'%(i,threadName))
time.sleep(2)
print('子线程结束')
if __name__ == '__main__':
mainThreadName = threading.current_thread().getName()
_thread.start_new_thread(method,("python",))
for i in range(10):
print('我是主线程(%d)@%s'%(i,mainThreadName))
time.sleep(1)
# while True:
# pass
print('主线程结束')
需要注意的是start_new_thread()传入的第一个参数为方法名(没有括号),第二个参数是参数元组(所以多了一个逗号)
子线程每次打印后睡眠2秒,主线程睡眠1秒
我是主线程(0)@MainThread
python
我是子线程(0)@Dummy-1
我是主线程(1)@MainThread
我是主线程(2)@MainThread
我是子线程(1)@Dummy-1
我是主线程(3)@MainThread
我是子线程(2)@Dummy-1
我是主线程(4)@MainThread
我是主线程(5)@MainThread
我是子线程(3)@Dummy-1
我是主线程(6)@MainThread
我是主线程(7)@MainThread
我是主线程(8)@MainThread
我是子线程(4)@Dummy-1
我是主线程(9)@MainThread
我是子线程(5)@Dummy-1
主线程结束
可见由于主线程完成只需要10秒钟,而子线程需要20秒,主线程一结束子线程也结束了。这是因为用start_new_thread()创建的子线程为守护线程!我们可以通过在主线程中死循环“阻塞”等待子线程完成打印。
2、threding.Thread()
Python3较为常用的是通过threading.Thread(Target=executable Method)-即传递给Thread对象一个可执行方法(或对象)来创建线程
def __init__(self, group=None, target=None, name=None,args=(), kwargs=None, *, daemon=None):
我们关注的参数是target和args,同样args是一个元组,并且deamon参数可以设置是否为守护线程。
并且创建完线程对象后调用start方法开启线程,则上面创建线程的代码可以改写为:
t = threading.Thread(target=method,args=("python",))
t.start()
运行结果
我是主线程(0)@MainThread
python
我是子线程(0)@Dummy-1
我是主线程(1)@MainThread
我是主线程(2)@MainThread
我是子线程(1)@Dummy-1
我是主线程(3)@MainThread
我是子线程(2)@Dummy-1
我是主线程(4)@MainThread
我是主线程(5)@MainThread
我是子线程(3)@Dummy-1
我是主线程(6)@MainThread
我是主线程(7)@MainThread
我是主线程(8)@MainThread
我是子线程(4)@Dummy-1
我是主线程(9)@MainThread
我是子线程(5)@Dummy-1
主线程结束
我是主线程(6)@MainThread
我是主线程(7)@MainThread
我是主线程(8)@MainThread
我是主线程(9)@MainThread
子线程结束
可见默认是非守护进程的,可以通过 setDeamon(True) 来设置为守护线程或是在初始化时声明
3、继承threading.Thread
继承threading.Thread定义子类并重写run()方法,可以在实例化的时候直接给参数,不向前两个方法通过元组来传参,所以可以重写init方法
import threading
import time
class MyThread(threading.Thread):
def __init__(self, name,task):
super().__init__()
self.name = name #自定义线程名字,覆盖了父类的name
self.task = task #自定义的属性,注意不要与父类中的属性重名
def run(self):
for i in range(10):
print('%s(%d)@%s' % (self.task ,i, threading.current_thread().getName()))
time.sleep(2)
print('子线程结束')
if __name__ == '__main__':
mt=MyThread('mythread','task')
mt.start()
for i in range(10):
print('我是主线程(%d)@%s' % (i, threading.current_thread().getName()))
time.sleep(1)
print('主线程结束')
运行结果
task(0)@mythread
我是主线程(0)@MainThread
我是主线程(1)@MainThread
我是主线程(2)@MainThread
task(1)@mythread
我是主线程(3)@MainThread
task(2)@mythread
我是主线程(4)@MainThread
我是主线程(5)@MainThread
task(3)@mythread
我是主线程(6)@MainThread
我是主线程(7)@MainThread
task(4)@mythread
我是主线程(8)@MainThread
我是主线程(9)@MainThread
task(5)@mythread
主线程结束
task(6)@mythread
task(7)@mythread
task(8)@mythread
task(9)@mythread
子线程结束
同样默认是非守护线程
二、几个API
thread.current_thread():返回当前正在运行的线程
threading.enumerate():返回当前活动进程的列表
threading.active_count():返回当前活动进程的个数
第一个上面已经使用过,可以试一试下面两个,在main方法中:
if __name__ == '__main__':
threading.Thread(target=method,args=('arg1',)).start()
threading.Thread(target=method, args=('arg1',)).start()
threading.Thread(target=method, args=('arg1',)).start()
tList = threading.enumerate()
print("当前活动线程:",tList)
# threading.active_count() = len(threading.enumerate())
tcount = threading.active_count()
print('当前活动线程有%d条'%(tcount))
运行结果
[<_MainThread(MainThread, started 5000)>, <Thread(Thread-1, started 68)>, <Thread(Thread-2, started 4316)>, <Thread(Thread-3, started 10456)>]
当前活动线程有4条
main方法也是一个线程,在main方法中创建了3个子线程,所以一共有4个线程。
在列表中每个元素中第一个参数是线程类型,main方法是_MainThread,第二个参数是线程名字,第三个参数started后面的数字是线程号即tid,可以通过 thread.current_thread().ident 获取
- .Net多线程编程—同步机制
- .Net多线程编程—Parallel LINQ、线程池
- 没有自己的服务器如何学习生物数据分析(下篇)
- .Net多线程编程—并发集合
- .Net多线程编程—任务Task
- 学会WCF之试错法——安全配置报错分析
- 生物信息学技能面试题(第5题)-根据GTF画基因的多个转录本结构
- 学会WCF之试错法——超时
- 学会WCF之试错法——客户端调用基础
- 【直播】我的基因组58:用R包SNPRelate来对我的基因型跟hapmap计划数据比较
- 生物信息学技能面试题(第4题)-多个同样的行列式文件合并起来
- PHP 底层的运行机制与原理
- asp.net web api 版本控制
- 如何编写更好的SQL查询:终极指南(上)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php 中self,this的区别和操作方法实例分析
- Laravel使用原生sql语句并调用的方法
- Yii框架自定义数据库操作组件示例
- laravel 使用事件系统统计浏览量的实现
- PHP之多条件混合筛选功能的实现方法
- PHP多进程简单实例小结
- 解决laravel5中auth用户登录其他页面获取不到登录信息的问题
- Yii框架学习笔记之应用组件操作示例
- laravel 之 Eloquent 模型修改器和序列化示例
- TP5框架请求响应参数实例分析
- laravel 模型查询按照whereIn排序的示例
- 解决在laravel中auth建立时候遇到的问题
- php array 转json及java 转换 json数据格式操作示例
- Thinkphp5 如何隐藏入口文件index.php(URL重写)
- 在Laravel中使用GuzzleHttp调用第三方服务的API接口代码