6. python实现多线程
多任务可以由多进程完成,也可以由一个进程内的多线程完成。线程是操作系统直接支持的执行单元,Python的标准库提供了两个模块_thread(低级模块)和threading(高级模块),大部分情况下选择用threading模块。
import time
import threading
# 新线程执行
def loop(num):
print(f"线程{threading.current_thread().name}正在运行...")
n = 0
while n < num:
n += 1
print(f"线程{threading.current_thread().name} >>> {n}")
time.sleep(1)
print(f"线程{threading.current_thread().name}结束")
print(f"线程{threading.current_thread().name}正在运行...")
t = threading.Thread(target=loop, name='LoopThread', args=(5,)) # 通过传参的方式调用局部变量
t.start()
t.join()
print(f"线程{threading.current_thread().name}运行结束.")
# 结果
'''
线程MainThread正在运行...
线程LoopThread正在运行...
线程LoopThread >>> 1
线程LoopThread >>> 2
线程LoopThread >>> 3
线程LoopThread >>> 4
线程LoopThread >>> 5
线程LoopThread结束.
线程MainThread运行结束.
'''
一个进程中的线程共享相同的内存单元、内存地址空间,可以访问相同的变量和对象,而且他们从同一堆中分配对象,通信、数据交换、同步操作,缺点线程是对全局变量随意修改,可能造成多线程之间对全局变量的混乱(不安全),可以通过传参的方式调用全局变量(不适用可变类型),但是修改次数过多,会有多次线程切换,产生紊乱。
# 给线程加锁,实现线程按顺序执行
from threading import Thread, Lock
import time
class Task1(Thread):
def run(self):
while True:
if lock1.acquire(): # 获取锁对象
print("--Task1--")
time.sleep(1)
lock2.release() # 释放锁
class Task2(Thread):
def run(self):
while True:
if lock2.acquire():
print("--Task2--")
time.sleep(1)
lock3.release()
class Task3(Thread):
def run(self):
while True:
if lock3.acquire():
print("--Task3--")
time.sleep(1)
lock1.release()
lock1 = Lock()
lock2 = Lock()
lock2.acquire()
lock3 = Lock()
lock3.acquire()
t1 = Task1()
t2 = Task2()
t3 = Task3()
t1.start()
t2.start()
t3.start()
# 结果
'''
--Task1--
--Task2--
--Task3--
--Task1--
--Task2--
--Task3--
.
.
.
'''
Thread对象的属性和方法
属性 | 描述 |
---|---|
****Thread对象数据属性**** | |
name | 线程名 |
ident | 线程的标识符 |
daemon | 布尔标志,表示这个线程是否是守护线程 |
****Thread对象方法**** | |
__init__(group=None, target=None, name=None, args=(), kwargs={}, verbose=None, daemon=None) | 实例化一个线程对象,需要有一个可调用的target ,以及其参数args 或者kwargs 。还可以传递name 或者group 参数,不过后者还未实现。此外,verbose 标志也是可选的,而daemon 的值将会设定thread.daemon 属性/标志。 |
start() | 开始执行线程 |
run() | 定义线程功能的方法(通常在子类中被应用开发者重写) |
join(timeout=None) | 直至启动线程终止之前一直挂起,除非给出了timeout,否则会一直阻塞 |
getName() | 返回线程名 |
setName(name) | 设定线程名 |
isAlivel/is_alive() | 布尔标志,表示这个进程是否还存活 |
isDaemon() | 如果是守护线程,则返回True,否则返回False |
setDaemon(daemonic) | 把线程的守护标志设定为布尔值daemonic (必须在线程start()之前调用 ) |