一个人的状态挺好的,想看书了就看书,累了就睡觉,想吃啥就吃啥,不想联系谁就自己安静一阵,出去旅行或是宅在家怎么都好。对爱情最好还是保持点儿洁癖,不要随便开始,不要急着妥协,真正值得的东西都不会那么轻易。珍惜还可以单身的日子吧,“不介意孤独,比爱你舒服”!
总结:
- 线程运行中的唯一:线程ID、线程内存地址;
1. threading.local类
下例使用多线程,每个线程完成不同的计算任务。
x是局部变量,可以看出每一个线程的x是独立的,互不干扰的,为什么?
能否改造成使用全局变量完成。
import threading
import time
import logging
FORMAT = "%(asctime)s %(threadName)s %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
# 局部变量实现
def worker():
x = 0
for _ in range(100):
time.sleep(0.0001)
x += 1
logging.info(x)
for i in range(10):
t = threading.Thread(target=worker,name='w-{}'.format(i))
t.start()
print("===============================")
#---------------------------------------------------------------------
===============================
2020-01-13 19:24:49,849 w-5 100
2020-01-13 19:24:49,849 w-1 100
2020-01-13 19:24:49,849 w-6 100
2020-01-13 19:24:49,849 w-4 100
2020-01-13 19:24:49,849 w-3 100
2020-01-13 19:24:49,849 w-7 100
2020-01-13 19:24:49,849 w-2 100
2020-01-13 19:24:49,849 w-0 100
2020-01-13 19:24:49,851 w-9 100
2020-01-13 19:24:49,851 w-8 100
# 全局实现方式1
import threading
import time
import logging
FORMAT = "%(asctime)s %(threadName)s %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
x = 0
def worker():
#x = 0
global x
for _ in range(100):
time.sleep(0.0001)
x += 1
logging.info(x)
for i in range(5):
t = threading.Thread(target=worker,name='w-{}'.format(i))
t.start()
print("===============================")
#-------------------------------------------------------------------------------------------
===============================
2020-01-13 19:30:49,065 w-1 489
2020-01-13 19:30:49,067 w-3 494
2020-01-13 19:30:49,067 w-2 495
2020-01-13 19:30:49,070 w-4 498
2020-01-13 19:30:49,072 w-0 500
# 全局实现方式2
import threading
import time
import logging
FORMAT = "%(asctime)s %(threadName)s %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
class A:
def __init__(self):
self.x = 0
a = A()
def worker():
#x = 0
#global x
for _ in range(100):
time.sleep(0.0001)
a.x += 1
logging.info(a.x)
for i in range(5):
t = threading.Thread(target=worker,name='w-{}'.format(i))
t.start()
print("===============================")
上例虽然使用了全局对象,但是线程之间互相干扰,导致了不期望的结果。
能不能既使用全局对象,还能保持每个线程使用不同的数据呢?
python提供 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据,其他线程看不见。
import threading
import time
import logging
FORMAT = "%(asctime)s %(threadName)s %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
class A:
def __init__(self):
self.x = 0
a = threading.local()
#a = A()
def worker():
#x = 0
#global x
a.x = 0
for _ in range(100):
time.sleep(0.0001)
a.x += 1
logging.info(a.x)
for i in range(5):
t = threading.Thread(target=worker,name='w-{}'.format(i))
t.start()
print("===============================")
#----------------------------------------------------------------------------------------
===============================
2020-01-13 19:54:59,524 w-2 100
2020-01-13 19:54:59,524 w-3 100
2020-01-13 19:54:59,525 w-0 100
2020-01-13 19:54:59,525 w-4 100
2020-01-13 19:54:59,526 w-1 100
结果显示和使用局部变量的效果一样。 再看threading.local的例子
import threading
X = 'abc'
ctx = threading.local() # 注意这个对象所处的线程
ctx.x = 123
print(ctx, type(ctx), ctx.x)
def worker():
print(X)
print(ctx)
print(ctx.x)
print('working')
worker() # 普通函数调用
print()
threading.Thread(target=worker).start() # 另起一个线程;
#---------------------------------------------------------------------------------
从运行结果来看,另起一个线程打印ctx.x出错了。
AttributeError: '_thread._local' object has no attribute 'x'
但是,ctx打印没有出错,说明看到ctx,但是ctx中的x看不到,这个x不能跨线程。
threading.local类构建了一个大字典,存放所有线程相关的字典,定义如下:
{ id(Thread) -> (ref(Thread), thread-local dict) }
每一线程实例的id为key,元组为value。
value中2部分为,线程对象引用,每个线程自己的字典。
本质
运行时,threading.local实例处在不同的线程中,就从大字典中找到当前线程相关键值对中的字典,覆盖
threading.local实例的 dict 。
这样就可以在不同的线程中,安全地使用线程独有的数据,做到了线程间数据隔离,如同本地变量一样安
全。
2. 定时器 Timer/延迟执行
threading.Timer继承自Thread,这个类用来定义延迟多久后执行一个函数;
本质上:还是启动了一个线程执行;
class threading.Timer(interval, function, args=None, kwargs=None)
start方法执行之后,Timer对象会处于等待状态,等待了interval秒之后,开始执行function函数的;
import threading
import logging
import time
FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(level=logging.INFO, format=FORMAT)
def worker():
logging.info('in worker')
time.sleep(2)
t = threading.Timer(4, worker)
t.setName('timer')
# t.cancel()
t.start()
t.cancel()
while True:
print(threading.enumerate())
time.sleep(1)
#--------------------------------------------------------------------------------------------
Timer提供了cancel方法,用来取消一个未执行的函数,如果上面例子中worker函数已经开始执行,cancel就没有任何效果了;
总结
Timer是线程Thread的子类,就是线程类,具有线程的能力和特征;
它的实例是能够延时执行目标函数的线程,在真正执行目标函数之前,都可以cancel它。
cancel方法本质使用Event类实现。这并不是说,线程提供了取消的方法。
网友评论