1. 程式人生 > >Python Multi-Processing多執行緒程式設計

Python Multi-Processing多執行緒程式設計

今天總結一下Python的Multi-Processing多執行緒程式設計。

建立多程序的方法

start new thread

使用thread.start_new_thread是一種最簡單的建立多程序的方法。

#!/usr/bin/python

import thread
import time

# Define a function for the thread
def print_time(threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print
"%s: %s"%(threadName, time.ctime(time.time())) # Create two threads as follows try: thread.start_new_thread(print_time, ("Thread-1", 2,)) thread.start_new_thread(print_time, ("Thread-2", 4,)) except: print "Error: unable to start thread" while 1: pass

輸出結果為:

Thread-1: Wed Sep 27 19
:52:57 2017 Thread-2: Wed Sep 27 19:52:59 2017 Thread-1: Wed Sep 27 19:52:59 2017 Thread-1: Wed Sep 27 19:53:01 2017 Thread-1: Wed Sep 27 19:53:03 2017 Thread-2: Wed Sep 27 19:53:03 2017 Thread-1: Wed Sep 27 19:53:05 2017 Thread-2: Wed Sep 27 19:53:07 2017 Thread-2: Wed Sep 27 19:53:11 2017 Thread-2: Wed Sep 27 19
:53:15 2017

如果沒有程式末尾的while無限迴圈,thread1和thread2之外的主執行緒瞬間就會結束,程式就退出了,因此會什麼也不列印。

threading module

#!/usr/bin/python

import threading
import time

exitFlag = 0

class myThread(threading.Thread):

   def __init__(self, threadID, name, delay):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.delay = delay

   def run(self):
      print "Starting " + self.name
      print_time(self.name, 5, self.delay)
      print "Exiting " + self.name

def print_time(threadName, counter, delay):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print "%s: %s" % (threadName, time.ctime(time.time()))
      counter -= 1

# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# Start new Threads
thread1.start()
thread2.start()

print "Exiting Main Thread"

輸出結果為:

Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Wed Sep 27 20:00:16 2017
Thread-2: Wed Sep 27 20:00:17 2017
Thread-1: Wed Sep 27 20:00:17 2017
Thread-1: Wed Sep 27 20:00:18 2017
Thread-2: Wed Sep 27 20:00:19 2017
Thread-1: Wed Sep 27 20:00:19 2017
Thread-1: Wed Sep 27 20:00:20 2017
Exiting Thread-1
Thread-2: Wed Sep 27 20:00:21 2017
Thread-2: Wed Sep 27 20:00:23 2017
Thread-2: Wed Sep 27 20:00:25 2017
Exiting Thread-2

也可以通過加入執行緒列表的形式,等待執行緒執行結束後主執行緒才退出:

#!/usr/bin/python

import threading
import time

exitFlag = 0

class myThread(threading.Thread):

   def __init__(self, threadID, name, delay):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.delay = delay

   def run(self):
      print "Starting " + self.name
      print_time(self.name, 5, self.delay)
      print "Exiting " + self.name

def print_time(threadName, counter, delay):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print "%s: %s" % (threadName, time.ctime(time.time()))
      counter -= 1

# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# Start new Threads
thread1.start()
thread2.start()

# Add threads to thread list
threads = []
threads.append(thread1)
threads.append(thread2)

# Wait for all threads to complete
for t in threads:
    t.join()

print "Exiting Main Thread"

輸出結果為:

Starting Thread-1
Starting Thread-2
Thread-1: Wed Sep 27 20:04:21 2017
Thread-1: Wed Sep 27 20:04:22 2017
Thread-2: Wed Sep 27 20:04:22 2017
Thread-1: Wed Sep 27 20:04:23 2017
Thread-2: Wed Sep 27 20:04:24 2017
Thread-1: Wed Sep 27 20:04:24 2017
Thread-1: Wed Sep 27 20:04:25 2017
Exiting Thread-1
Thread-2: Wed Sep 27 20:04:26 2017
Thread-2: Wed Sep 27 20:04:28 2017
Thread-2: Wed Sep 27 20:04:30 2017
Exiting Thread-2
Exiting Main Thread

互斥鎖同步執行緒

不加鎖的問題

當不同的執行緒操作同一批資料的時候,就有可能產生意想不到的問題。比如說:

# encoding: UTF-8
import threading
import time

class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
        num = num+1
        msg = self.name+' set num to '+str(num)
        print msg
num = 0
threads = []
def test():
    for i in range(1000):
        t = MyThread()
        t.start()
    threads.append(t)
if __name__ == '__main__':
    test()
    for t in threads:
        t.join()
    print num

理論上說,一千個執行緒都讓num增1,結果應該是1000,但是輸出的結果不是1000:(而且每次都不一樣)

............
Thread-998 set num to 905
Thread-988 set num to 906
Thread-994 set num to 904
Thread-992 set num to 901
Thread-990 set num to 907
Thread-1000 set num to 908
908

這是因為不同執行緒同時操作同樣資料導致的執行緒不同步。此時需要通過加互斥鎖實現執行緒的同步。

加鎖的效果

# encoding: UTF-8
import threading
import time

class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
    threadLock.acquire() 
        num = num+1
    threadLock.release()
        msg = self.name+' set num to '+str(num)
        print msg
num = 0
threadLock = threading.Lock()
threads = []
def test():
    for i in range(1000):
        t = MyThread()
        t.start()
    threads.append(t)
if __name__ == '__main__':
    test()
    for t in threads:
        t.join()
    print num

加鎖相當於每個資料在每一時刻只能被一個執行緒獲取到,而獲取不到鎖的執行緒就會處於暫時的阻塞狀態。輸出結果是這樣的:

.........
Thread-994 set num to 994
Thread-995 set num to 995
Thread-993 set num to 993
Thread-996 set num to 996
Thread-999 set num to 997
Thread-1000 set num to 998
Thread-998 set num to 999
Thread-997 set num to 1000
1000

可以看出,並不是按照執行緒的建立時間獲取資料的處理許可權,但是結果卻可以保證每個執行緒都能依次處理資料,從而保證資料被自增了1000次。