1,Thread Local类的用法
python 中多线程的并发跟其他语言一样,需要考虑多线程并发访问去全局变量所带来的问题,python的local类解决了这个问题,通过它让每个线程内部有一个相对独立的local保存数据,某一个线程修改了数据,不影响其他线程中保存的数据。
1 from threading import Thread 2 import threading 3 import time 4 local_value=threading.local() 5 local_value.x='en' 6 class threadtest(Thread): 7 8 def __init__(self,num): 9 Thread.__init__(self) 10 self.num=num 11 12 def run(self): 13 local_value.x=self.getName() 14 for i in range(self.num): 15 time.sleep(1) 16 print(local_value) 17 18 19 threadtest(3).start() 20 threadtest(2).start()
执行结果是:
Thread-1 Thread-2 Thread-1 Thread-2 Thread-1 [Finished in 3.2s]
这表明,虽然两个线程公用一个local_value.x但是确实相互独立的变量。
另外,
local_value.x=self.getName()放在__init__()中时,运行会报错,说'_thread._local' object has no attribute 'x',目测是因为在初始化__init__的时候,线程还没有建立local_value对象,只有在__init__执行完之后,才可以开始赋值(不过对于这一点我不确定,看源码也看晕了)。
2,Thread join()方法的用法及含义:
join()源码中的解释:
"""Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates -- either normally or through an unhandled exception or until the optional timeout occurs. When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call isAlive() after join() to decide whether a timeout happened -- if the thread is still alive, the join() call timed out. When the timeout argument is not present or None, the operation will block until the thread terminates. A thread can be join()ed many times. join() raises a RuntimeError if an attempt is made to join the current thread as that would cause a deadlock. It is also an error to join() a thread before it has been started and attempts to do so raises the same exception. """
当某个子线程调用join()时,主线程将阻塞,直至该线程执行完毕,
当每个子线程调用都join(),且不设置参数时
from threading import Thread import threading import time local_value=threading.local() class threadtest(Thread): def __init__(self,num): Thread.__init__(self) self.num=num #local_value.x=self.getName() def run(self): local_value.x=self.getName() for i in range(self.num): time.sleep(1) print(local_value.x) from threading import current_thread #print(current_thread(),local_value.__dict__,'--') a=threadtest(2) b=threadtest(2) c=threadtest(2) a.start() a.join() b.start() b.join() c.start() c.join() for i in range(2): time.sleep(1) print(current_thread())
结果是:
Thread-1 Thread-1 Thread-2 Thread-2 Thread-3 Thread-3 <_MainThread(MainThread, started 6688)> <_MainThread(MainThread, started 6688)> [Finished in 8.2s]
即:哪个子线程先调用join,就先完成它的任务,依次执行,不仅是主线程,其他的子线程也必须为调用了join的线程让路,让它执行完毕,在执行下一个调用了join的子线程,最后才轮到主线程上台(主线程:卧槽,我才是老大啊!)
如果每个子线程都设置时间参数,但是时间参数小于完成任务所需的时间的话
from threading import Thread import threading import time local_value=threading.local() class threadtest(Thread): def __init__(self,num): Thread.__init__(self) self.num=num #local_value.x=self.getName() def run(self): local_value.x=self.getName() for i in range(self.num): time.sleep(1) print(local_value.x) from threading import current_thread #print(current_thread(),local_value.__dict__,'--') a=threadtest(6) b=threadtest(6) #c=threadtest(6) a.start() b.start() a.join(2) b.join(2) #c.start() #c.join(2) #以下是主线程 for i in range(2): #ime.sleep(1) print(current_thread())
结果为:
Thread-1
Thread-2
Thread-1
Thread-2
Thread-1
Thread-2
Thread-1
Thread-2
<_MainThread(MainThread, started 8652)>
<_MainThread(MainThread, started 8652)>
Thread-1
Thread-2
Thread-1
Thread-2
[Finished in 6.2s]
从结果可以看出,子线程开始确实阻塞了主线程,但是没有阻塞其他子线程,所以两个子线程仍然是并行执行,一共阻塞了4秒钟(线程1,和线程2一起),四秒钟后程序开始执行join之后的代码,也就是主线程的代码,从这之后,主线程和子线程之间是并行关系。
总结一下(不要告诉我你只看总结)
1,子线程只要调用了join函数,就会阻塞主线程,不管有没有设置参数,
2,子线程如果调用join函数,设置了时间参数,主线程在设置的时间内被阻塞,子线之间一直是并行的,时间到了后,程序将会执行join()之后的代码。
3,如果子线程调用join函数,没有设置时间参数,那么子线程之间不会并行,而是有优先成那个调用了join的子线程。
如果不调用join,那么主线程不会为子线程阻塞,所有线程并发执行。