Python3使用线程

Python2标准库中提供了两个模块thread和threading支持多线程。
thread有一些缺陷在Python3中弃用,为了兼容性,python3 将 thread 重命名为 "_thread",在Python3中推荐直接使用threading。

创建线程对象

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

参数说明:

group 应该为 None;为了日后扩展 ThreadGroup 类实现而保留。
target 是用于 run() 方法调用的可调用对象。默认是 None,表示不需要调用任何方法。
name 是线程名称。默认情况下,由 "Thread-N" 格式构成一个唯一的名称,其中 N 是小的十进制数。
args 是用于调用目标函数的参数元组。默认是 ()。
kwargs 是用于调用目标函数的关键字参数字典。默认是 {}。
如果 daemon 不是 None,线程将被显式的设置为 守护模式,不管该线程是否是守护模式。如果是 None (默认值),线程将继承当前线程的守护模式属性。

线程对象其中的几个方法

start()开始线程活动。
run() 代表线程活动的方法。
join(timeout=None) 等待,直到线程终结
setDaemon()设置是否为守护线程

一、使用线程有两种方式:函数或者用类来包装线程对象

例子1:使用函数

import random
import threading 
import time

def run(threadName):
    for i in range(5):
        time.sleep(random.random())
        #这里只是演示参数,获取当前线程名可用threading.currentThread().getName()
        print('{} : {}'.format(threadName, i))

t1 = threading.Thread(target=run, args=('thread 1',))
t1.start()
t2 = threading.Thread(target=run, args=('thread 2',))
t2.start()

'''
运行结果:
thread 2 : 0
thread 2 : 1
thread 1 : 0
thread 1 : 1
thread 2 : 2
thread 2 : 3
thread 1 : 2
thread 1 : 3
thread 2 : 4
thread 1 : 4
'''

例子2:使用类(运行结果和例子1类似)

import random
import threading 
import time

class test(threading.Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name
    def run(self):
        for i in range(5):
            time.sleep(random.random())
            print('{} : {}'.format(self.name, i))
        
t1 = test('thread 1')
t1.start()
t2 = test('thread 2')
t2.start()

二、join(timeout=None) 方法

一个进程启动之后,会默认产生一个主线程A,当创建子线程B后,如果不调用B.join(),则主线程A和子线程B会同时执行;
如果调用B.join()则主线程会在调用处等待子线程B执行完后,才继续往下执行。
参数timeout是可选的,代表线程运行的最大时间,如果超过这个时间,不管这个线程有没有执行完毕都会被回收,然后主线程会接着执行。
join在start后才调用。

1、不调用子线程join方法

import random
import threading 
import time

def run():
    name = threading.currentThread().getName()
    print('{} start'.format(name))
    time.sleep(random.random())
    print('{} end'.format(name))

threads = []
for i in range(5):
    threads.append(threading.Thread(target=run))

for th in threads:
    th.start()

print("finished")

'''
运行结果
Thread-1 start
Thread-2 start
Thread-3 start
Thread-4 start
Thread-5 startfinished

Thread-5 end
Thread-3 end
Thread-2 end
Thread-4 end
Thread-1 end
'''

2、调用子线程join方法

import random
import threading 
import time

def run():
    name = threading.currentThread().getName()
    print('{} start'.format(name))
    time.sleep(random.random())
    print('{} end'.format(name))

threads = []
for i in range(5):
    threads.append(threading.Thread(target=run))

for th in threads:
    th.start()

#等待,直到线程终结。
for th in threads:
    th.join()

print("finished")

'''
运行结果
Thread-1 start
Thread-2 start
Thread-3 start
Thread-4 start
Thread-5 start
Thread-3 end
Thread-5 end
Thread-4 end
Thread-1 end
Thread-2 end
finished
'''

三、setDaemon()方法

主线程A中创建子线程B后,如果调用B.setDaemon(),把子线程设置为守护线程。
表示主线程A一旦执行结束,不管子线程B是否执行完成,会全部被终止。
setDaemon和join相反,在start之前设置。

备注:
主线程在其它非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将会被回收,而进程必须保证非守护线程都运行完毕后才能结束。
所以如果存在多个子线程,假设有守护线程B,又有非守护线程C,则主线程会等待非守护线程C执行完,守护线程B如果还没执行完则会被终止。

import threading 
import time

def run():
    name = threading.currentThread().getName()
    print('{} start'.format(name))
    time.sleep(2)
    #下面这行代码因为主线程已经执行结束,被终止执行
    print('{} end'.format(name))

print("start")

t = threading.Thread(target=run)
t.setDaemon(True)
t.start()

time.sleep(1)

print("finished")

'''
运行结果
start
Thread-1 start
finished
'''

 四、线程锁

每个线程互相独立,相互之间没有任何关系,但是在同一个进程中的资源,线程是共享的,如果不进行资源的合理分配,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。
下面例子,如果不用线程锁Lock,则每次得到的结果都不一样。

from threading import Thread, Lock
lock = Lock()
total = 0

#如果不使用lock那么,最后得到的数字不一定为0;
def cal(type):
    global total    
    for i in range(1000000):
        lock.acquire() 
        if(type == '+'):
            total += 1
        else:
            total -= 1
        lock.release()
    
thread1 = Thread(target=cal,args=('+',))
thread2 = Thread(target=cal,args=('-',))
thread1.start()
thread2.start()
thread1.join()
thread2.join()

print(total)
原文地址:https://www.cnblogs.com/gdjlc/p/11425406.html