Python 多线程Threading

jopen 4年前

不喜欢废话,先上今天的代码!

#-*- 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 —)

来自: http://my.oschina.net/CandyMi/blog/599165