Python multi-thread 多線程 print 如何避免print的結果混亂


multithread如何寫

這是我第一次寫multithread,所以就是照着例子學,下面是我用來學的例子

來自於”Automate the boring stuff with Python”的15.6

import threading, time

print "Start of the program"

def takeANap():
     time.sleep(5)
     print "Wake up!"

thread1 = threading.Thread(target = takeANap)
thread1.start()


print "End of the program"

OK, 這個小程序的結果會是End of… 這一句先print出來,然后Wake up再出現,其實”Automate the boring….”這本書里對多線程就講了兩個例子,這是第一個,第二個是講了如何向多線程傳遞參數,但是看完之后發現對今天的程序幫助不大,因為今天的程序有很大的一部分困難就是print造成的,那么下面就說說源程序的需求和第一次失敗的嘗試。

以一個多線程print的程序為例子

  • 需求:
    使用多線程,在三台不同的路由器上,show arp並輸出

  • 問題:
    很明顯,輸出會messed up, 因為線程各自有快有慢

  • 初步想到的方法

  • 可以把兩個的結果存到外部文件,然后有條理的讀取,然后有條理的print。我認為這樣是可行的,但是這樣顯然練習不到multithread的特征,因為multithread是關乎內存的,存到磁盤再讀,感覺上有些違背了充分利用多線程的優勢,況且這是一個小程序,就是純粹顯示的問題。

  • threading.Lock()

先說,這個失敗了,因為print比較特殊,它自己的打印快慢依然會影響,這不是一個線程是否被執行完的問題,而是一個線程執行完了之后,它的輸出打印並不夠快而如何解決的問題,所以Lock()幫不上忙

Lock()的相關代碼:

我依照這個鏈接里的例子創建了自己的thread的子類

  • 這個myThread會以device類,也就是某個路由器為對象,調取printARP

  • 我在print的前后分別加了acquire()用於上鎖和release()用於解鎖

class myThread(threading.Thread):
  def __init__(self, device):
  threading.Thread.__init__(self)
  self.device = device
  def run(self):
  threadLock1 = threading.Lock()
  threadLock1.acquire()
  printARP(self.device)
  threadLock1.release()

然后調用子類,開啟各個子類實例化出來的thread, 把各個thread放進一個數組,數組分別調用 .join()

thread1 = myThread(rtr1)
thread2 = myThread(rtr2)
thread3 = myThread(srx)

thread1.start()
thread2.start()
thread3.start()

threads = []
threads.append(thread1)
threads.append(thread2)
threads.append(thread3)


for t in threads:
  t.join()

print "All done"

然而並沒有卵用,哪怕是你用了 .join讓他們分別回歸主線程,一會兒再說join()的事情。

  • 最后的解決辦法
  • sys.stdout.write(a_string)

對,就是這個貨,我從這個鏈接看到的,最后那個答案就是

原話如下

‘The issue is that python uses seperate opcodes for the NEWLINE printing and the printing of the object itself. The easiest solution is probably to just use an explicit sys.stdout.write with an explicit newline.’

然后下面有個評論是sys.stdout.write的用法

‘From my recent experience, this is absolutely true. I’m not exactly sure why it happens, but the printstatement (even when STDOUT is properly serialized and flushed) will output erratic newlines. You must usesys.stdout.write(s + ‘\n’) to avoid this. ‘

當然下面還有個評論是跟上面這位仁兄說依然需要lock的,但是anyway,這個sys.stdout.write(a_string)解決了我的問題

  • 最后的代碼是這樣的
  • 不使用自己定義的子類了,依然使用自帶的threading.Thread()創建新thread
  thread1 = threading.Thread(target=printARP, args=[rtr1])
  thread2 = threading.Thread(target=printARP, args=[rtr2])
  thread3 = threading.Thread(target=printARP, args=[srx])

然后剩下的都一樣

  • 唯一需要改動的地方

printARP這個功能模塊,改成如下,把print改成sys.stdout.write() 記得引入sys

def printARP(device):
  ''' print the ARP table on this device '''
  conn = ConnectHandler(**device)
  #sys.stdout.flush()

  arp = conn.send_command("show arp")
  time.sleep(1)
  outp = ("ARP table on %s :" % get_name_of_obj(device, "each_device")+"\n")
  # use find_prompt() to determin the output of threads are not messed up
  outp += (conn.find_prompt()+"\n")
  outp += (arp+"\n")
  outp += "*********************\n"
  sys.stdout.write(outp)

完整的代碼在這里

線程的join

差點忘了說了,這個答主的答案特別好,那個圖簡直絕了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM