Python学习笔记:线程的创建

时间:2019-02-19
本文章向大家介绍Python学习笔记:线程的创建,主要包括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 获取