Python中的multiprocessing和threading

时间:2023-03-08 17:49:51
Python中的multiprocessing和threading

Python中的multiprocessing和threading分别使用来实现多进程编程和多线程编程的。其中threading比较简单,而前者比较繁琐。

下面,我们进行一下分析:

多线程——threading

最简单的多线程编程的例子

上代码:

import threading

def threading_func(name):
print "This is Function %s" % (name) if __name__ == '__main__':
threadings = []
for i in xrange(1, 5):
temp_thread = threading.Thread(target=threading_func, args=(str(i),))
threadings.append(temp_thread)
temp_thread.start()
for one_thread in threadings:
one_thread.join()

这个程序执行的结果为:

This is Function 1
This is Function 2
This is Function 3
This is Function 4
[Finished in 0.1s]

其中可以看到几个Thread类的使用方法,

  1. 使用list来记录所有的线程
  2. 声明一个线程时使用的方法为threading.Thread(target=xxx ,args=(xxx))其中这个target填写的是该线程中简要运行的方法名,args中要以元组的形式给出这个方法的参数。
  3. 使用start()方法来开始这个线程
  4. 使用join()方法来“合并线程”,合并的意思是:若在线程A中执行了C.join(),表示在C执行完毕后再去A中的join后开始执行。我们在主线程中一次调用所有线程的join(),表示所有线程均结束后,后面的语句才可以执行。与这个函数容易混淆的是setDaemon(True),Daemon是“后台”的意思,这个函数(True时)可以将一个线程设置为“后台线程”,主线程不考虑子线程的执行,一旦主线程执行完毕,则被终止,同时终止所有子线程的执行。当然,setDaemon(True)join()不同的是,前者需要在start()方法被调用前执行。另外,在join()方法中还可以设置Timeout,当join()方法没有设置Timeout时,主调线程会一直被阻塞到被调线程结束,若设置Timeout的话,则主调线程会被阻塞Timeout所设定的时间。

创建进程除了上面说的那种方法以外,还有另外一种方法,集成Thread类,具体写法如下:

import threading

class MyThread(threading.Thread):
def __init__(self, ...):
threading.Thread.__init__(self)
self.xxx = ... # 设置其他属性 def run(self):
# code

将线程需要执行的代码全部放在run函数的code处即可。

进程通信

目前我只是搞了搞简单的进程通信,使用event类。

import threading
import time class MyThread(threading.Thread): def __init__(self, signal):
threading.Thread.__init__(self)
self.signal = signal def run(self):
print "I am %s, I will sleep" % (self.name)
self.signal.wait()
print "I an %s, I awake" % (self.name) if __name__ == '__main__':
signal = threading.Event()
for t in xrange(0, 3):
thread = MyThread(signal)
thread.start() print "main thread sleep 3 seconds"
time.sleep(3) signal.set()

这种写法就是上面所说的那种集成thread类的写法,signal是一个threading.Event()类型的变量,所有进程都执行到self.signal.wait()这里后等待signal被设置,当主进程执行到signal.set()时,会设置signal,表示发送了一个信号,唤醒全部阻塞在signal.wait()的进程,这叫做进程通信。更多内容等待以后学习。

进程互斥

有时候,我们希望两个进程不要同时更改一个资源,这时候我们就需要加上互斥锁mutex。代码如下:

import threading
import time counter = 0
mutex = threading.Lock() class MyThread(threading.Thread): def __init__(self):
# super(MyThread, self).__init__(self)
threading.Thread.__init__(self)
self.setName("Big Thread" + self.name) def run(self):
global counter, mutex
time.sleep(1)
if mutex.acquire():
counter += 1
print "I am %s, set counter %d" % (self.name, counter)
mutex.release() if __name__ == '__main__':
for i in xrange(200):
my_thread = MyThread()
my_thread.start()

在每一个run函数中,都有以下方法:

mutex.acquire()获得锁,即加上锁。mutex.release释放锁,即解锁。当无法获得锁时,进程将会被阻塞,直到获得锁。上述代码执行结果为:

I am Big ThreadThread-1, set counter 1
I am Big ThreadThread-5, set counter 2
I am Big ThreadThread-2, set counter 3
I am Big ThreadThread-4, set counter 4
I am Big ThreadThread-3, set counter 5
[Finished in 1.0s]

可见counter这个变量是按照顺序加的,尽管进程号不是递增的。若我们将所有关于所的代码注释掉,得到以下代码:

I am Big Thread Thread-1, set counter 1
I am Big Thread Thread-2, set counter 2
I am Big Thread Thread-3, set counter 3
I am Big Thread Thread-6, set counter 4
I am Big Thread Thread-8, set counter 5I am Big Thread Thread-5, set counter 6
I am Big Thread Thread-10, set counter 7 I am Big Thread Thread-9, set counter 9
I am Big Thread Thread-7, set counter 8
I am Big Thread Thread-4, set counter 10
[Finished in 1.0s]

结构非常混乱。