不喜欢废话,先上今天的代码!
#-*- 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 —)
来源:oschina
链接:https://my.oschina.net/u/2420772/blog/599165