Python之threading模块的使用
作用:同一个进程空间并发运行多个操作,专业术语简称为:【多线程】
1、任务函数不带参数多线程
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading def worker(): print('worker...') threads = [] for i in range(3): task = threading.Thread(target=worker) threads.append(task) task.start() print(threads)
运行效果
[root@ mnt]# python3 threading_simple.py worker... worker... worker... [<Thread(Thread-1, stopped 140040860006144)>, <Thread(Thread-2, stopped 140040860006144)>, <Thread(Thread-3, stopped 140040860006144)>]
2、任务函数带参数多线程
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading def worker(num): print('worker %s...' % num) threads = [] for i in range(3): task = threading.Thread(target=worker, args=(i,)) threads.append(task) task.start() print(threads)
运行效果
[root@ mnt]# python3 threading_simple_args.py worker 0... worker 1... worker 2... [<Thread(Thread-1, stopped 140326829315840)>, <Thread(Thread-2, stopped 140326829315840)>, <Thread(Thread-3, stopped 140326829315840)>]
3、线程标识名字设置和获取
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time def worker(): print(threading.current_thread().getName(), 'Starting') time.sleep(0.2) print(threading.current_thread().getName(), 'Exiting') def my_service(): print(threading.current_thread().getName(), 'Starting') time.sleep(0.3) print(threading.current_thread().getName(), 'Exiting') my_service_task = threading.Thread(name='my_service', target=my_service) worker_task = threading.Thread(name='worker', target=worker) default_task = threading.Thread(target=worker) # 使用默认的名字Thread-1 my_service_task.start() worker_task.start() default_task.start()
运行效果
[root@ mnt]# python3 threading_name.py my_service Starting worker Starting Thread-1 Starting worker Exiting Thread-1 Exiting my_service Exiting
4、线程标识名字设置和获取,利用logging模块打印出来日志,调试一般不建议用print打印出来
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import logging def worker(): logging.debug('Starting') time.sleep(0.2) logging.debug('Exiting') def my_service(): logging.debug('Starting') time.sleep(0.3) logging.debug('Exiting') logging.basicConfig( level=logging.DEBUG, # 以下格式化,参考官方文档:https://docs.python.org/3/library/logging.html format='[%(levelname)s] (%(thread)d) (%(threadName)-10s) %(message)s', ) my_service_task = threading.Thread(name='my_service', target=my_service) worker_task = threading.Thread(name='worker', target=worker) default_task = threading.Thread(target=worker) # 使用默认的名字Thread-1 my_service_task.start() worker_task.start() default_task.start()
运行效果
[root@ mnt]# python3 threading_name_logging.py [DEBUG] (140555433457408) (my_service) Starting [DEBUG] (140555354896128) (worker ) Starting [DEBUG] (140555346503424) (Thread-1 ) Starting [DEBUG] (140555354896128) (worker ) Exiting [DEBUG] (140555346503424) (Thread-1 ) Exiting [DEBUG] (140555433457408) (my_service) Exiting
5、守护线程随着主程序退出而关闭线程
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import logging def daemon(): logging.debug('daemon Starting...') time.sleep(0.2) logging.debug('daemon Exiting...') def non_daemon(): logging.debug('non_daemon Starting...') logging.debug('non_daemon Exiting...') logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s' ) daemon_task = threading.Thread(name='daemon', target=daemon, daemon=True) #设置为首护线程 non_daemon_task = threading.Thread(name='non_daemon_task', target=non_daemon) daemon_task.start() non_daemon_task.start()
运行效果
[root@mnt]# python3 threading_daemon.py (daemon ) daemon Starting... (non_daemon_task) non_daemon Starting... (non_daemon_task) non_daemon Exiting... #由于守护线程还没有执行完,主进程已退出,守护线程即随之被终止,从而导致【daemon Exiting...】没打印出来
6、等待守护线程运行结束,才关闭主程序
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import logging def daemon(): logging.debug('daemon Starting...') time.sleep(0.2) logging.debug('daemon Exiting...') def non_daemon(): logging.debug('non_daemon Starting...') logging.debug('non_daemon Exiting...') logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s' ) daemon_task = threading.Thread(name='daemon', target=daemon, daemon=True) # 设置为首护线程 non_daemon_task = threading.Thread(name='non_daemon_task', target=non_daemon) daemon_task.start() non_daemon_task.start() daemon_task.join() non_daemon_task.join()
运行效果
[root@ mnt]# python3 threading_daemon_join.py
(daemon ) daemon Starting...
(non_daemon_task) non_daemon Starting...
(non_daemon_task) non_daemon Exiting...
(daemon ) daemon Exiting...
#由于使用的join等待线程运行完成,才结束,所以【daemon Exiting...】可以打印出来
7、设置守护线程的超时时间,防止进入无限阻塞
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import logging def daemon(): logging.debug('daemon Starting...') time.sleep(0.2) logging.debug('daemon Exiting...') def non_daemon(): logging.debug('non_daemon Starting...') logging.debug('non_daemon Exiting...') logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s' ) daemon_task = threading.Thread(name='daemon', target=daemon, daemon=True) # 设置为首护线程 non_daemon_task = threading.Thread(name='non_daemon_task', target=non_daemon) daemon_task.start() non_daemon_task.start() daemon_task.join(0.1) #设置的超时时间0.1秒,因为该任务的函数睡眠0.2s,所以没有运行完成,就已经超时,结束该守护线程 print('isAlive()', daemon_task.isAlive()) non_daemon_task.join()
运行效果
[root@ mnt]# python3 threading_daemon_join_timeout.py
(daemon ) daemon Starting...
(non_daemon_task) non_daemon Starting...
(non_daemon_task) non_daemon Exiting...
isAlive() True #这里是判断线程是否在运行,True表在线程还在运行
8、利用threading.enumerate()枚举的方法,设置守护线程等待运行完成
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import logging import random def worker(): pause = random.randint(1, 5) / 10 logging.debug('睡眠 %0.2f 秒', pause) time.sleep(pause) logging.debug('worker 结束') logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s' ) for i in range(3): task = threading.Thread(target=worker, daemon=True) task.start() main_thread = threading.main_thread() for task_obj in threading.enumerate(): #threading.enumerate():返回当前运行守护线程的实例 if task_obj is main_thread: continue logging.debug('等待 %s', task_obj.getName()) task_obj.join()
运行效果
[root@ mnt]# python3 threading_enumerate.py (Thread-1 ) 睡眠 0.30 秒 (Thread-2 ) 睡眠 0.10 秒 (Thread-3 ) 睡眠 0.10 秒 (MainThread) 等待 Thread-1 (Thread-2 ) worker 结束 (Thread-3 ) worker 结束 (Thread-1 ) worker 结束 (MainThread) 等待 Thread-2 (MainThread) 等待 Thread-3
9、利用继承threading.Thread类,实现无参的多线程
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging class MyThread(threading.Thread): def run(self): logging.debug('运行...') logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s', ) for i in range(5): task = MyThread() task.start()
运行效果
[root@ mnt]# [root@python-mysql mnt]# python3 threading_subclass.py (Thread-1 ) 运行... (Thread-2 ) 运行... (Thread-3 ) 运行... (Thread-4 ) 运行... (Thread-5 ) 运行...
10、利用继承threading.Thread类,实现有参的多线程
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging class MyThread(threading.Thread): def __init__(self, group=None, target=None, name=None, daemon=None, args=(), kwargs=None): super(MyThread, self).__init__(group=group, target=target, name=name, daemon=daemon) self.args = args self.kwargs = kwargs def run(self): logging.debug('运行...args : %s,kwargs : %s', self.args, self.kwargs) logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s', ) for i in range(5): task = MyThread(args=(i,), kwargs={'a': 'A', 'b': 'B'}) task.start()
运行效果
[root@ mnt]# python3 threading_subclass_args.py (Thread-1 ) 运行...args : (0,),kwargs : {'a': 'A', 'b': 'B'} (Thread-2 ) 运行...args : (1,),kwargs : {'a': 'A', 'b': 'B'} (Thread-3 ) 运行...args : (2,),kwargs : {'a': 'A', 'b': 'B'} (Thread-4 ) 运行...args : (3,),kwargs : {'a': 'A', 'b': 'B'} (Thread-5 ) 运行...args : (4,),kwargs : {'a': 'A', 'b': 'B'}
11、定时器线程threading.Timer
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time def delayed(): logging.debug('delayed运行...') logging.basicConfig( level=logging.DEBUG, format="(%(threadName)-10s) %(message)s" ) task_1 = threading.Timer(0.3, delayed) task_1.setName('task_1') task_2 = threading.Timer(0.3, delayed) task_2.setName('task_2') logging.debug('开始运行Timer') task_1.start() task_2.start() logging.debug('取消前等待') time.sleep(0.2) logging.debug('取消 %s' % task_2.getName()) task_2.cancel() logging.debug('取消完成')
运行效果
[root@ mnt]# python3 threading_timer.py
(MainThread) 开始运行Timer
(MainThread) 取消前等待
(MainThread) 取消 task_2
(MainThread) 取消完成
(task_1 ) delayed运行...
#task_2已经被取消,所以没有运行
12、线程间信号相互传送threading.Event
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time def wait_for_event(event_obj): logging.debug('等待事件的开始') event_is_set = event_obj.wait() logging.debug('事件设置 %s' % event_is_set) def wait_for_event_timeout(event_obj, timeout): while not event_obj.is_set(): logging.debug('等待事件超时开始') event_is_set = event_obj.wait(timeout) if event_is_set: logging.debug('处理事件') else: logging.debug('做其他工作') logging.basicConfig( level=logging.DEBUG, format="(%(threadName)-10s) %(message)s" ) event_obj = threading.Event() task_1 = threading.Thread( name='block', target=wait_for_event, args=(event_obj,) ) task_1.start() task_2 = threading.Thread( name='nonblock', target=wait_for_event_timeout, args=(event_obj, 2) ) task_2.start() logging.debug('在呼叫前等待 Event.set()') time.sleep(0.3) event_obj.set() logging.debug('事件已经设置')
运行效果
[root@ mnt]# python3 threading_event.py
(block ) 等待事件的开始
(nonblock ) 等待事件超时开始
(MainThread) 在呼叫前等待 Event.set()
(MainThread) 事件已经设置
(block ) 事件设置 True
(nonblock ) 处理事件
13、控制资源访问_计数器_多线程加阻塞锁的示例
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time import random class Counter(object): def __init__(self, start=0): self.lock = threading.Lock() self.value = start def increment(self): logging.debug('等待锁') self.lock.acquire() try: logging.debug('获取锁') self.value += 1 finally: self.lock.release() def worker(c): for i in range(2): pause = random.random() logging.debug('睡眠 %0.02f', pause) time.sleep(pause) c.increment() logging.debug('worker运行结束') logging.basicConfig( level=logging.DEBUG, format="(%(threadName)-10s) %(message)s" ) counter = Counter() for i in range(2): t = threading.Thread(target=worker, args=(counter,)) t.start() logging.debug('等待线程worker运行结束') main_thread = threading.main_thread() for t in threading.enumerate(): if t is not main_thread: t.join() logging.debug('Counter: %d', counter.value)
运行效果
[root@mnt]# python3 threading_lock.py (Thread-1 ) 睡眠 0.36 (Thread-2 ) 睡眠 0.77 (MainThread) 等待线程worker运行结束 (Thread-1 ) 等待锁 (Thread-1 ) 获取锁 (Thread-1 ) 睡眠 0.43 (Thread-2 ) 等待锁 (Thread-2 ) 获取锁 (Thread-2 ) 睡眠 0.12 (Thread-1 ) 等待锁 (Thread-1 ) 获取锁 (Thread-1 ) worker运行结束 (Thread-2 ) 等待锁 (Thread-2 ) 获取锁 (Thread-2 ) worker运行结束 (MainThread) Counter: 4 #运行4次,所以显示4
14、控制资源访问_计数器_多线程非阻塞锁的示例
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time def lock_holder(lock_obj): logging.debug('lock_holder 开始') while True: lock_obj.acquire() try: logging.debug('Holding') time.sleep(0.5) finally: logging.debug('Not Holding') lock_obj.release() time.sleep(0.5) def worker(lock_obj): logging.debug('worker 开始') num_tries = 0 num_acquires = 0 while num_acquires < 3: time.sleep(0.5) logging.debug('尝试获取锁') have_it = lock_obj.acquire(0) # 主要核心代码在这里,不断尝试获取锁,通过这个判断锁是否释放可以获取 try: num_tries += 1 if have_it: logging.debug('重试次数 %d: 得到锁', num_tries) num_acquires += 1 else: logging.debug('重试次数 %d: 没有得到锁', num_tries) finally: if have_it: lock_obj.release() logging.debug('获取锁一共尝试的 %d 次', num_tries) logging.basicConfig( level=logging.DEBUG, format="(%(threadName)-10s) %(message)s" ) lock = threading.Lock() holder = threading.Thread( target=lock_holder, args=(lock,), name='LockHolder', daemon=True, ) holder.start() worker = threading.Thread( target=worker, args=(lock,), name='Worker', ) worker.start()
运行结果
[root@ mnt]# python3 threading_lock_nonblock.py (LockHolder) lock_holder 开始 (LockHolder) Holding (Worker ) worker 开始 (LockHolder) Not Holding (Worker ) 尝试获取锁 (Worker ) 重试次数 1: 得到锁 (LockHolder) Holding (Worker ) 尝试获取锁 (Worker ) 重试次数 2: 没有得到锁 (LockHolder) Not Holding (Worker ) 尝试获取锁 (Worker ) 重试次数 3: 得到锁 (LockHolder) Holding (Worker ) 尝试获取锁 (Worker ) 重试次数 4: 没有得到锁 (LockHolder) Not Holding (Worker ) 尝试获取锁 (Worker ) 重试次数 5: 得到锁 (Worker ) 获取锁一共尝试的 5 次 #尝试的次数是随机,这样子的好处,不会因为阻塞占有CPU资源
15、互斥锁
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading lock = threading.Lock() print('第一个锁', lock.acquire()) print('第二个锁', lock.acquire(0))
运行效果
[root@ mnt]# python3 threading_lock_reacquire.py 第一个锁 True 第二个锁 False
16、同步锁
import threading lock = threading.RLock() print('第一个锁', lock.acquire()) print('第二个锁', lock.acquire(0))
运行效果
[root@ mnt]# python3 threading_rlock.py
第一个锁 True
第二个锁 True
17、利用with管理锁,无需每次都释放锁lock.release()
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging def worker_with(lock): with lock: logging.debug('当前运行是用with 获取锁') def worker_no_with(lock): lock.acquire() try: logging.debug('当前运行是用 lock.acquire() 获取锁') finally: lock.release() logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s', ) lock = threading.Lock() with_open_lock = threading.Thread(target=worker_with, args=(lock,)) no_with_open_lock = threading.Thread(target=worker_no_with, args=(lock,)) with_open_lock.start() no_with_open_lock.start()
运行效果
[root@ mnt]# python3 threading_with_lock.py (Thread-1 ) 当前运行是用with 获取锁 (Thread-2 ) 当前运行是用 lock.acquire() 获取锁
18、利用threading.Condition(),实现线程同步,下面是生产者和消费者的示例
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time def consumer(condition_obj): """消费者""" logging.debug('消费者线程开启') with condition_obj: condition_obj.wait() logging.debug('资源可供消费者使用。') def producer(condition_obj): """生产者""" logging.debug('生产者线程开启') with condition_obj: logging.debug('生产可用资源') condition_obj.notifyAll() logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s', ) condition_obj = threading.Condition() # 消费者实例1 c1 = threading.Thread( name='c1', target=consumer, args=(condition_obj,) ) # 消费者实例1 c2 = threading.Thread( name='c2', target=consumer, args=(condition_obj,) ) # 生产者实例 p = threading.Thread( name='p', target=producer, args=(condition_obj,) ) c1.start() time.sleep(0.2) c2.start() time.sleep(0.2) p.start()
运行效果
[root@ mnt]# python3 threading_condition.py
(c1 ) 消费者线程开启
(c2 ) 消费者线程开启
(p ) 生产者线程开启
(p ) 生产可用资源
(c1 ) 资源可供消费者使用。
(c2 ) 资源可供消费者使用。
19、线程同步threading.Barrier() ,作用:等待所有线程一起开启后,再全部一起执行主要的功能
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time def worker(barrier): logging.debug('当前线程名字: %s 与 %s 其他人一起等待后面的功能' % (threading.current_thread().name, barrier.n_waiting)) worker_id = barrier.wait() logging.debug('%s 已经等待完毕 %s' % (threading.current_thread().name, worker_id)) logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s', ) NUM_THREADS = 3 barrier = threading.Barrier(NUM_THREADS) threads = [ threading.Thread( name='worker-%s' % i, target=worker, args=(barrier,) ) for i in range(NUM_THREADS) ] # 这里是实例化3个线程,[<Thread(worker-0, initial)>, <Thread(worker-1, initial)>, <Thread(worker-2, initial)>] for thread_obj in threads: logging.debug('%s 开启' % thread_obj.name) thread_obj.start() time.sleep(0.2) for thread_obj in threads: thread_obj.join()
运行效果
[root@ mnt]# python3 threading_barrier.py (MainThread) worker-0 开启 (worker-0 ) 当前线程名字: worker-0 与 0 其他人一起等待后面的功能 (MainThread) worker-1 开启 (worker-1 ) 当前线程名字: worker-1 与 1 其他人一起等待后面的功能 (MainThread) worker-2 开启 (worker-2 ) 当前线程名字: worker-2 与 2 其他人一起等待后面的功能 (worker-2 ) worker-2 已经等待完毕 2 (worker-0 ) worker-0 已经等待完毕 0 (worker-1 ) worker-1 已经等待完毕 1
20、线程同步barrier.abort()中断的操作,作用:等待所有线程运行后面的功能,然后对它进行中断的操作,使用停止运行
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time def worker(barrier): logging.debug('当前线程名字: %s 与 %s 其他人一起等待后面的功能' % (threading.current_thread().name, barrier.n_waiting)) try: worker_id = barrier.wait() except threading.BrokenBarrierError: logging.debug('%s 中断', threading.current_thread().name) else: logging.debug('%s 已经等待完毕 %s' % (threading.current_thread().name, worker_id)) logging.basicConfig( level=logging.DEBUG, format='(%(threadName)-10s) %(message)s', ) NUM_THREADS = 3 # barrier.abort()必须多加一个线程,所以这里需要加1 barrier = threading.Barrier(NUM_THREADS + 1) threads = [ threading.Thread( name='worker-%s' % i, target=worker, args=(barrier,) ) for i in range(NUM_THREADS) ] # 这里是实例化3个线程,[<Thread(worker-0, initial)>, <Thread(worker-1, initial)>, <Thread(worker-2, initial)>] for thread_obj in threads: logging.debug('%s 开启' % thread_obj.name) thread_obj.start() time.sleep(0.1) #中断线程一起同步运行 barrier.abort() for thread_obj in threads: thread_obj.join()
运行效果
[root@ mnt]# python3 threading_barrier_abort.py (MainThread) worker-0 开启 (worker-0 ) 当前线程名字: worker-0 与 0 其他人一起等待后面的功能 (MainThread) worker-1 开启 (worker-1 ) 当前线程名字: worker-1 与 1 其他人一起等待后面的功能 (MainThread) worker-2 开启 (worker-2 ) 当前线程名字: worker-2 与 2 其他人一起等待后面的功能 (worker-0 ) worker-0 中断 (worker-1 ) worker-1 中断 (worker-2 ) worker-2 中断
21、threading.Semaphore(),自定义线程池
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import logging import time class ActivePool(object): """活动池""" def __init__(self): self.active = [] self.lock = threading.Lock() def makeActive(self, name): """获取一个锁,把活动的名字增加于列表中""" with self.lock: self.active.append(name) logging.debug('运行:%s' % self.active) def makeInactive(self, name): with self.lock: self.active.remove(name) logging.debug('运行:%s', self.active) def worker(semaphore_obj, pool): logging.debug('正在等待加入池') with semaphore_obj: name = threading.current_thread().getName() pool.makeActive(name) time.sleep(0.1) pool.makeInactive(name) logging.basicConfig( level=logging.DEBUG, format='%(asctime)s (%(threadName)-10s) %(message)s', ) pool = ActivePool() semaphore_obj = threading.Semaphore(2) for i in range(4): t = threading.Thread( target=worker, name=str(i), args=(semaphore_obj, pool) ) t.start()
运行效果
[root@ mnt]# python3 threading_semaphore.py 2019-12-08 15:31:47,387 (0 ) 正在等待加入池 2019-12-08 15:31:47,387 (0 ) 运行:['0'] 2019-12-08 15:31:47,388 (1 ) 正在等待加入池 2019-12-08 15:31:47,389 (1 ) 运行:['0', '1'] 2019-12-08 15:31:47,389 (2 ) 正在等待加入池 2019-12-08 15:31:47,390 (3 ) 正在等待加入池 2019-12-08 15:31:47,489 (0 ) 运行:['1'] 2019-12-08 15:31:47,491 (1 ) 运行:[] 2019-12-08 15:31:47,492 (2 ) 运行:['2'] 2019-12-08 15:31:47,494 (3 ) 运行:['2', '3'] 2019-12-08 15:31:47,593 (2 ) 运行:['3'] 2019-12-08 15:31:47,596 (3 ) 运行:[]
22、threading.local(),本地线程任务运行隔离
#!/usr/bin/env python # -*- coding: utf-8 -*- import random import threading import logging def show_value(local_obj): try: val = local_obj.value except AttributeError: logging.debug('值不存在') else: logging.debug('value=%s', val) def worker(local_obj): show_value(local_obj) local_obj.value = random.randint(1, 100) show_value(local_obj) logging.basicConfig( level=logging.DEBUG, format='%(asctime)s (%(threadName)-10s) %(message)s', ) local_obj = threading.local() # 第一次运行没有设置value值,会报AttributeError异常 show_value(local_obj) # 第二次运行有设置value值,所以会显示出值 local_obj.value = 1000 show_value(local_obj) for i in range(2): t = threading.Thread( target=worker, args=(local_obj,), ) t.start()
运行效果
[root@ mnt]# python3 threading_local.py 2019-12-08 16:23:17,696 (MainThread) 值不存在 2019-12-08 16:23:17,697 (MainThread) value=1000 2019-12-08 16:23:17,697 (Thread-1 ) 值不存在 2019-12-08 16:23:17,698 (Thread-1 ) value=26 2019-12-08 16:23:17,698 (Thread-2 ) 值不存在 2019-12-08 16:23:17,698 (Thread-2 ) value=39
23、threading.local(),本地线程任务运行隔离,初始化全局变量值
#!/usr/bin/env python # -*- coding: utf-8 -*- import random import threading import logging def show_value(local_obj): try: val = local_obj.value except AttributeError: logging.debug('值不存在') else: logging.debug('value=%s', val) def worker(local_obj): show_value(local_obj) local_obj.value = random.randint(1, 100) show_value(local_obj) logging.basicConfig( level=logging.DEBUG, format='%(asctime)s (%(threadName)-10s) %(message)s', ) class MyLocal(threading.local): def __init__(self, value, *args, **kwargs): super(MyLocal, self).__init__(*args, **kwargs) logging.debug('初始化值 %r', self) self.value = value local_obj = MyLocal(1000) show_value(local_obj) for i in range(2): t = threading.Thread( target=worker, args=(local_obj,) ) t.start()
测试效果
[root@ mnt]# python3 threading_local.default.py 2019-12-08 16:28:48,168 (MainThread) 初始化值 <__main__.MyLocal object at 0x7fe58b6e1408> 2019-12-08 16:28:48,168 (MainThread) value=1000 2019-12-08 16:28:48,169 (Thread-1 ) 初始化值 <__main__.MyLocal object at 0x7fe58b6e1408> 2019-12-08 16:28:48,169 (Thread-1 ) value=1000 2019-12-08 16:28:48,169 (Thread-1 ) value=11 2019-12-08 16:28:48,170 (Thread-2 ) 初始化值 <__main__.MyLocal object at 0x7fe58b6e1408> 2019-12-08 16:28:48,170 (Thread-2 ) value=1000 2019-12-08 16:28:48,170 (Thread-2 ) value=7