2017-08-25 99 views
1

我已經創建了帶有多線程的python腳本,每個線程都向全局dict寫入值,這是線程安全的,因爲每個線程都使用新的唯一值更新字典,我不希望每個線程都保存在輸出文件中的字典的結果,但我收到「字典在迭代過程中改變大小」,有沒有辦法做到這一點,如鎖定字典在轉儲到文件時寫入,我試圖鎖定和釋放,但沒有工作python多線程保存字典結果

def do_function(): 
    while True: 
     r=q.get() 
     global_dict[r]={} --> this is thread safe as r is unique it will not repeat again 
     telephone,address=get_info(r) 
     global_dict[r]['t']=telephone 
     global_dict[r]['a']=address 

     with open("output.pickle","wb") as j: --> save to file 
       pickle.dump(global_dict,j) --> receive error dictionary changed size during iteration 

     q.task_done() 

global dict={} 
thread=10 
q = Queue(threads * 2) 
for i in range(concurrent): 
    t = Thread(target=do_function) 
    t.daemon = True 
    t.start() 
for p in lst: 
     q.put(p) 
    q.join() 
+0

您提供的兩行代碼是無效的Python,並且它們也不會形成[mcve]。告訴我們什麼沒有工作。 –

+0

重複? https://stackoverflow.com/questions/1312331/using-a-global-dictionary-with-threads-in-python – Alexander

+0

不重複,我已經看到了這一點,它談到哪些操作在字典中是線程安全的,哪一個你應該鎖定並釋放 – Amr

回答

0

您不需要在線程中執行寫入字典。也許這是一個錯誤。 因爲這是一個全球字典。您可以在所有線程完成後執行此操作,只需將

with open("output.pickle","wb") as j: 
    pickle.dump(global_dict,j) 

移動到文件末尾。

你的錯誤是由當一個線程被傾銷到文件的字典引起的,而另一個線程改變了字典,所以在迭代

編輯了1

第一個線程會抱怨字典改變大小

我認爲簡單的解決辦法是不要使用全局變量,那麼錯誤不會發生。 這樣的:

import threading 
lock = threading.Lock() 

def do_function(): 
    while True: 
     r=q.get() 
     d={} 
     telephone,address=get_info(r) 
     d['t']=telephone 
     d['a']=address 
     lock.acquire() 
     with open("output.pickle","ab") as j: 
       pickle.dump(d,j) 
     lock.release() 
     q.task_done() 

,並注意使用「AB」模式打開文件進行追加不更換,不使用「WB」。

組織編寫

使用鎖定每次寫入文件可能有沉重的代價。解決方法是將每個線程寫入到不同的文件中,該文件可以通過進入該線程時生成的uuid命名。

而更快的方法是當寫時,您可以進行批量寫入和使用鎖定。它會比老年人更快。

示例代碼:

import threading 
lock = threading.Lock() 

def do_function(): 
    buffer = [] 
    while True: 
     r=q.get() 
     d={} 
     telephone,address=get_info(r) 
     d['t']=telephone 
     d['a']=address 
     buffer.append(d) 
     q.task_done() 

     if len(buffer) >= BATCH_COUNT: 
      lock.acquire() 
      with open("output.pickle","ab") as j: 
        pickle.dump(buffer,j) 
      lock.release() 
      buffer = [] 

的BATCH_COUNT可能是1000或10000,或者你喜歡的東西。

+0

是的,我知道,我想不斷地將它寫入文件,而不是在所有線程完成之後,如果程序崩潰了,它不需要從頭開始重複,它會從它離開的地方繼續,是有辦法做到這一點? – Amr

+0

答案更新了,希望能幫到你 – GuangshengZuo

+0

所有的線程同時寫入一個文件,我認爲這會使文件不可讀,內容會重疊,或者寫入文件是線程安全的? – Amr