一. 创建并执行线程
1. threading.Thead
直接创建
用Thread(target=函数名)创建线程对象,用start根据线程对象创建线程并执行。
import threading
from threading import Thread
def hello():
print("hello world")
import time
time.sleep(1)
if __name__ == "__main__":
# 创建线程对象
t = Thread(target=hello)
# 执行线程
t.start()
# 查看所有的线程
print(threading.enumerate())
结果;
hello world
[<_MainThread(MainThread, started 4640308672)>, <Thread(Thread-1, started 123145556144128)>]
2. 继承Thread并覆盖run方法
import threading
from threading import Thread
class HelloThread(Thread):
def run(self):
print("hello world")
import time
time.sleep(1)
if __name__ == "__main__":
# 创建线程对象
t = HelloThread()
# 执行线程
t.start()
# 查看所有的线程
print(threading.enumerate())
结果:
hello world
[<_MainThread(MainThread, started 4657499584)>, <HelloThread(Thread-1, started 123145479835648)>]
二. 多线程共享全局变量
多线程中的变量共享与单线程的变量共享在直觉上相同。
多线程是共享全局变量的
from threading import Thread
NUM = 1
def add_num():
global NUM
NUM += 1
print("NUM in add_num is ", NUM)
def print_num():
print("NUM in print_num is ", NUM)
if __name__ == "__main__":
t1 = Thread(target=add_num)
t2 = Thread(target=print_num)
t1.start()
# 主线程等待t1执行完毕
t1.join()
t2.start()
print("NUM in main is ", NUM)
结果
NUM in add_num is 2
NUM in print_num is 2
NUM in main is 2
局部作用域
from threading import Thread
def add_num(number):
number += 1
print("NUM in add_num is ", number)
def append_3(list_):
list_.append(3)
print("list in append_3 is ", list_)
def print_num(number):
print("NUM in print_num is ", number)
def print_list(list_):
print("list in print_list is ", list_)
if __name__ == "__main__":
def start_and_join(t):
t.start()
t.join()
# 测试传入可变类型
a_list = [1, 2]
t_list = Thread(target=append_3, args=(a_list, ))
t_print_list = Thread(target=print_list, args=(a_list, ))
start_and_join(t_list)
start_and_join(t_print_list)
print("list in main is ", a_list)
print()
# 测试传入变量不可变类型
a_number = 10
t_number = Thread(target=add_num, args=(a_number, ))
t_print_number = Thread(target=print_num, args=(a_number, ))
start_and_join(t_number)
start_and_join(t_print_number)
print("number in main is ", a_number)
共享全局变量的问题 - 资源竞争
from threading import Thread
NUMBER = 0
LOOP = 10 ** 6
def add_number1():
global NUMBER
for i in range(LOOP):
NUMBER += 1
print("number in add_num1 is ", NUMBER)
def add_number2():
global NUMBER
for i in range(LOOP):
NUMBER += 1
print("number in add_num2 is ", NUMBER)
if __name__ == "__main__":
t1 = Thread(target=add_number1)
t2 = Thread(target=add_number2)
t1.start()
t2.start()
t1.join()
t2.join()
print("number in main is ", NUMBER)
结果
number in add_num1 is 1331562
number in add_num2 is 1336960
number in main is 1336960
使用互斥锁解决资源竞争的问题
互斥锁
- 创建:
mutex = threading.Lock()
- 锁定:
mutex.acquire()
- 释放:
mutex.release()
from threading import Thread, Lock
NUMBER = 0
LOOP = 10 ** 6
mutex = Lock()
def add_number1():
global NUMBER
for i in range(LOOP):
mutex.acquire()
NUMBER += 1
mutex.release()
print("number in add_num1 is ", NUMBER)
def add_number2():
global NUMBER
for i in range(LOOP):
mutex.acquire()
NUMBER += 1
mutex.release()
print("number in add_num2 is ", NUMBER)
if __name__ == "__main__":
t1 = Thread(target=add_number1)
t2 = Thread(target=add_number2)
t1.start()
t2.start()
t1.join()
t2.join()
print("number in main is ", NUMBER)
死锁
当有多个锁时,两方互相等待锁释放,这时就会产生死锁。
避免死锁的方法:
- 银行家算法,在程序设计时避免死锁
- 添加超时等待时间