线程局部变量
为了解决多线程竞争资源的问题,threading提供了一个local()函数,该函数返回一个线程局部变量,实际上就是为每一个使用该变量的线程都提供一个变量的副本
import threading
from concurrent.futures import ThreadPoolExecutor
# 定义线程局部变量
mydata = threading.local()
# 定义准备作为线程执行体使用的函数
def action (max):
for i in range(max):
try:
mydata.x += i
except:
mydata.x = i
# 访问mydata的x的值
print('%s mydata.x的值为: %d' %
(threading.current_thread().name, mydata.x))
# 使用线程池启动两个子线程
with ThreadPoolExecutor(max_workers=2) as pool:
pool.submit(action , 10)
pool.submit(action , 10)
线程局部变量从另一个角度来解决多线程的并发访问问题,但并不能替代同步机制,两者解决的问题不同,同步机制是为了同步多个线程对共享资源的并发访问,是多个线程之间进行通信的有效方式,线程局部变量是为了隔离多个线程的数据共享,从根本上避免多个线程之间对共享资源(变量)的竞争,因此如果多个线程之间需要共享资源,以实现线程通信,则使用同步机制,如果仅仅许愿哦隔离多个线程之间的共享冲突,则使用局部变量
定时器
Thread类提供了一个Timer子类,该子类可用于控制指定函数在特定时间内执行一次
from threading import Timer
def hello():
print("hello, world")
# 指定10秒后执行hello函数
t = Timer(10.0, hello)
t.start()
from threading import Timer
import time
# 定义总共输出几次的计数器
count = 0
def print_time():
print("当前时间:%s" % time.ctime())
global t, count
count += 1
# 如果count小于10,开始下一次调度
if count < 10:
t = Timer(1, print_time)
t.start()
# 指定1秒后执行print_time函数
t = Timer(1, print_time)
t.start()
如果程序想取消Timer的调度,则可调用Timer对象的cancel()函数
任务调度
如果要执行更复杂的任务调度,可以使用Python提供的sched模块,该模块提供了sched.schedule类,它就是任务调度器
sched.schedule类构造器
sched.scheduler(timefunc=time.monotonic, delayfunc=time.sleep)构造器接受两个参数
- timefunc:该参数指定生成时间戳的时间函数,默认使用time.monotonic来生成时间戳
- dealyfunc:该参数指定阻塞程序的函数,默认调用time.sleep函数来阻塞程序
sched.schedule类函数和属性
- scheduler.enterabs(time, priority, action, argument=(), kwargs={}):指定在time时间点执行action函数,argument和kwargs都用于向action函数传入参数,其中argument使用位置参数的形式传入参数,kwargs使用关键字参数的形式传入参数;该方法返回一个event,它可作为cancel()方法的参数用于取消调度,priority参数指定该任务的优先级,当在同一个时间点有多个任务需要执行时,优先级高(值越小越高)的任务优先执行
- scheduler.enter(delay, priority, action, argument=(), kwargs={}):该方法与上一个方法基本相同,只是delay参数用于指定多少秒后执行action任务
- scheduler.cancel(event):判断当前该调度器的调度队列是否为空
- scheduler.run(blocking=True):运行所有需要调度的任务,如果调用该方法的blocking参数为Ture,则该方法将会阻塞线程,直到所有被调度的任务都执行完毕
- scheduler.queue:该只读属性返回该调度器的调度序列
代码示例
import sched, time
import threading
# 定义线程调度器
s = sched.scheduler()
# 定义被调度的函数
def print_time(name='default'):
print("%s 的时间: %s" % (name, time.ctime()))
print('主线程:', time.ctime())
# 指定10秒之后执行print_time函数
s.enter(10, 1, print_time)
# 指定5秒之后执行print_time函数,优先级为2
s.enter(5, 2, print_time, argument=('位置参数',))
# 指定5秒之后执行print_time函数,优先级为1
s.enter(5, 1, print_time, kwargs={'name': '关键字参数'})
# 执行调度的任务
s.run()
print('主线程:', time.ctime())
执行结果为
C:\Users\davieyang\Downloads\codes\14\14.8>python sched_test.py
主线程: Wed Apr 29 01:22:27 2020
关键字参数 的时间: Wed Apr 29 01:22:32 2020
位置参数 的时间: Wed Apr 29 01:22:32 2020
default 的时间: Wed Apr 29 01:22:37 2020
主线程: Wed Apr 29 01:22:37 2020