python之多线程

做一个python多线程的笔记。。。。

0x00 首先是多进程与多线程

google了一下,一个程序从开始运行到结束,算是一个进程,正常情况CPU一个核心同一时间只能运行一个进程,所以涉及到多进程(我还没到这个层次,这里就不多说了)。一个进程运行过程中,运行的’路径’叫做线程,正常情况,一个程序运行从头到位都是只有一条路劲,叫单线程。而这篇博文写的就是如何用python写一个多线程的程序。

0x01 python多线程的简单使用

使用的是threading模块 import threading

在我的理解中,多线程和孙悟空一样会生猴子,’孙悟空’在’主干道’上执行代码,从头执行到尾,遇到一个函数就会生一个小猴子,去执行这个函数。举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import time
import threading
def music():
for i in range(2):
print 'I was listening to music. %s' %time.ctime()
time.sleep(1)
def movi():
for i in range(2):
print 'I was at the movies! %s' %time.ctime()
time.sleep(5)

if __name__=='__main__':
music()
movi()
print 'all over %s' %time.ctime()

上图就是’主干道’,我把正常情况下,比喻成磨蹭的唐僧。
‘唐僧’遇到music()代码,会调到music()函数中去执行,执行完后又跳出来,然后遇到movi()又跳进去,执行完跳出来,然后执行print 'xxx'.
下面把执行这串代码的变成’孙悟空’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import time
import threading
def music():
for i in range(2):
print 'I was listening to music. %s' %time.ctime()
time.sleep(1)
def movi():
for i in range(2):
print 'I was at the movies! %s' %time.ctime()
time.sleep(5)

if __name__=='__main__':
s = threading.Thread
a=s(target=music)
b=s(target=movi)
a.start();b.start()
b.join()
print 'all over %s' %time.ctime()

上面这串代码中threading.Thread(target=函数)就是’孙悟空’的分身术,然后start()就是该分身跳进函数中去执行该函数,而join()函数相当于一面挡路的墙,’孙悟空’只有和指定的分身回合后才能打通这面墙。。
下面再写个通过类创建分身的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import time
import threading
class test(threading.Thread): #定义一个类test为threading.Thread的子类
def __init__(self):
threading.Thread.__init__(self)     #覆盖threading.Thread的__init__属性
def run(self):                  #覆盖run属性
print 'hehe',time.ctime()
time.sleep(2)
print 'abc'
#只需要覆盖__init__,run两个方法就够了。start方法用来激活run方法
if __name__=='__main__':
a = test()
a.start()
a.join()
print 'hh'

等理解的更深入了再更新博客~~
==================update time : 24/3==================

今天看了看python类的用法,对上面的用法也大致了解了。。就在上文的代码中加些注释。。

0x02 Queue模块

Queue是队列操作模块,用于线程之间的数据交换,举个例子,子线程1从文件中读取数据,然后存入Queue —> Queue.Queue.put(xxx) #把xxx放入Queue
然后子线程2,进行读取Queue中的内容进行其他操作,比如写入另一个文件。。还是上一串代码吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import threading
from Queue import Queue

class readfile(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global isFinal
f = open('file1.txt')
a = Queue()
for eachline in f:
a.put(eachline)
f.close()
isFinal = 1
class writefile(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global isFinal
f = open('file2.txt','w')
b = Queue()
while True:
if b.empty() and isFinal:
break
cont = b.get()     #get()每次会从Queue队列中获取一行信息,所以需要循环
f.write(cont)
f.close()
if __name__ =='__main__':
rea = readfile()
rea.start()
writ = writefile()
writ.start()

0x03 Lock 方法

多线程的程序会有一个问题,比如上面的代码中,writefile类有两个线程在运行,由于计算机处理速度很快,所以会出现这样一种情况:

Queue中只剩下一个,第一个线程进行b.empty()判断,为false,还没执行到b.get()的时候,第二个线程也执行了b.empty(),同样返回false,然后前面的线程get()到了内容,第二个线程由于Queue队列里没有数据了,进行get()操作将会报错。这是很糟糕的情况。

因此,就有了Lock方法。。举个例子。

线程一读取队列中数据之前,把锁锁上,然后进行判断b.empty(),执行b.get()。。然后释放锁。。在锁锁上的地方,线程二将会被卡在那,不会执行任何操作。直到解锁。贴以小串代码:

1
2
3
4
5
6
7
import threading
lock = threading.Lock()
if lock.acquire(): #如果lock处于未被锁定状态,则锁定lock,然后返回True。如果lock处于锁定状态,则不进行任何操作,由于既不会返回True也会返回False.所以if语句会被卡在这里,不进行任何操作
if b.empty() and isFinal:
break
cont = b.get()
lock.release() #解锁