Python 多线程Threading
不喜欢废话,先上今天的代码!
#-*- coding:utf-8 -*- import threading class MyThreading(threading.Thread): def __init__(self,num): threading.Thread.__init__(self) self.num = num def run(self): print self.num t = MyThreading(100) t.start() print t.isAlive()
乍一看,很简单的threading代码。首先我们继承了Thread类,在子类里初始化后又重写了run方法。最后我们实例化MyThreading子类,然后打印我们的num参数。最后再打印线程执行状态。
初学者一看,绝对分为2派:1、支持说先打印num参数,然后才打印线程状态。 2、拍胸脯保证先打印线程状态再打印num参数;
其实结果出人预料:
结果1:
C:\Python27\python.exe D:/ProjectSpace/thread-example.py 100True Process finished with exit code 0
结果2:
C:\Python27\python.exe D:/ProjectSpace/thread-example.py True100 Process finished with exit code 0
吃惊吗?也许每次运行结果可能会有几次相同,但是在运行10次内,至少会有1-4次不同结果。
答案:线程的执行将是无序的
带着上面的问题,我们继续看下面一个例子:
#-*- coding:utf-8 -*- import threading,time class MyThreading(threading.Thread): def __init__(self,num): threading.Thread.__init__(self) self.num = num def run(self): time.sleep(10) print self.num def function1(): t1.start() time.sleep(1) print "t1 thread was Destruction " def function2(): t2.start() time.sleep(1) print "t2 thread was Destruction " t1 = MyThreading(10) t2 = MyThreading(20) t2.setDaemon(True) function1() function2()
当你多次运行代码的时候,大概你能看到如下结果:
C:\Python27\python.exe D:/ProjectSpace/thread-example.py t1 thread was Destruction t2 thread was Destruction 10 Process finished with exit code 0
让我们看看单步调试运行下的结果是怎么样的:
C:\Python27\python.exe "C:\Program Files (x86)\JetBrains\PyCharm 5.0.3\helpers\pydev\pydevd.py" --multiproc --qt-support --client 127.0.0.1 --port 62267 --file D:/ProjectSpace/thread-example.py Connected to pydev debugger (build 143.1559) 10 t1 thread was Destruction 20 t2 thread was Destruction Process finished with exit code 0
是的, 你没有看错! 出现不同的结果的原因是:
Threadclass.setDeamon方法指定了一个线程为主线程;而主线程的作用是当它要退出时会先检查子进程是否完成,如果未完成则继续等待,完成则退出。
这也是为什么我们在Debug模式时走的是逻辑上的方法,而实际上在运行时的结果却如上所述。
那么问题来了!:我们如何保证程序的顺序执行呢?
为了保证线程的执行顺序或者说是为了保证一致性,针对线程的操作引入了同步的概念。而针对同步最好的办法也就是对操作进行加锁了。(加锁让我想起了MySQL的锁 - _ -)
请继续看下面的2个例子:
例1:
#-*- coding:utf-8 -*- import threading,time ####继承Thread类 class MyThreading(threading.Thread): def __init__(self,name): ####初始化父类 threading.Thread.__init__(self,name=name) def run(self): ####引入全局变量 global x ####给操作加锁 lock.acquire() for i in range(3): x = x + 1 time.sleep(3) print x ####操作完成并解锁 lock.release() ####实例化一个锁的类 lock = threading.RLock() ####定义一个空的线程类的列表 tl = [] ####实例化10个类,并且将类添加到tl这个类列表里 for i in range(10): t = MyThreading(str(i)) tl.append(t) ####初始化全局 x = 0 ####逐个执行所有已经实例化的线程 for i in tl: i.start()
输出结果如下
C:\Python27\python.exe D:/ProjectSpace/thread-example.py 3 6 9 12 15 18 21 24 27 30 Process finished with exit code 0
代码很简单,首先通过一个循环实例化10个类放进一个列表内,再从列表内遍历出来运行。 因为执行了加锁——》释放这个步骤。如果在time.sleep()时间内未到,release无法执行。所以我们能控制程序的顺序。
例2:
#-*- coding:utf-8 -*- import threading,time ####继承Thread类 class MyThreading(threading.Thread): def __init__(self,name): ####初始化父类 threading.Thread.__init__(self,name=name) def run(self): ####引入全局变量 global x ####给操作加锁 #lock.acquire() for i in range(3): x = x + 1 time.sleep(3) print x ####操作完成解锁 #lock.release() ####实例化一个锁的类 #lock = threading.RLock() ####定义一个空的线程类的列表 tl = [] ####实例化10个类,并且将类添加到tl这个类列表里 for i in range(10): t = MyThreading(str(i)) tl.append(t) ####初始化全局 x = 0 ####逐个执行所有已经实例化的线程 for i in tl: i.start()
输出结果如下
C:\Python27\python.exe D:/ProjectSpace/thread-example.py 30 30 30 30 30 30 30 30 30 30 Process finished with exit code 0
同例1一样,程序从列表拿出实例化的类运行;但是因为没对run方法进行加锁,所以线程运行到time.sleep()时不会等待就启动第二个....第三个.....直到最后一个。
而当run方法全部运行完毕后,并且计算出全局变量X的最终值,time.sleep时间到了;这时候X已经为30,所以每个X输出的值都是30了。
一个简单的Threading函数同步实例就说到这里! 下次见~~~ (— 3 —)