2012-02-07 126 views
7

我在python中編寫了一個多線程解壓縮程序。每個線程需要訪問不同的輸入文件塊。從python中的多個線程讀取單個文件

注1:無法加載整個文件,因爲它的範圍從15 Gb到200 Gb;我沒有使用多線程來加速數據讀取,但數據解壓縮,我只是想確保數據讀取不會減慢解壓。注意2:GIL不是問題,在這裏,由於主解壓縮函數是一個C擴展,它調用Py_ALLOW_THREADS,所以GIL在解壓縮時被釋放。第二階段減壓使用也是無GIL的numpy。

1)我認爲這是行不通的去分享一個解壓縮對象(這基本上包裝了一個文件對象),如果線程A調用以下日期:

decompressor.seek(x) 
decompressor.read(1024) 

和線程B不相同,螺紋A可能最終從線程B偏移量讀取。它是否正確?

2)現在我只是讓每個線程創建自己的Decompressor實例,它似乎工作,但我不知道這是最好的方法。 我考慮這些可能性:

  • 添加類似

    seekandread(from_where, length) 
    

    到獲取鎖時,尋求,讀取和釋放鎖解壓縮類;

  • 創建一個線程,等待讀取請求並按正確的順序執行它們。

那麼,我是否錯過了一個明顯的解決方案?這些方法之間是否存在顯着的性能差異?

感謝

+5

以多線程方式讀取文件實際上會減慢硬盤驅動器進程的速度。針必須從一個地方跳到另一個地方,而不是以迭代方式工作。您應該在處理文件之前加載文件。 – 2012-02-07 12:16:17

+0

無法加載整個文件,因爲它的範圍從15 Gb到200 Gb;我沒有使用多線程來加速數據讀取,但數據解壓縮,我只是想確保數據讀取不會減慢解壓。 – Alberto 2012-02-07 12:21:16

+0

當然,這可能或可能不適用於SSD。我不知道這個問題。您不應該在硬件上進行中繼。一旦SSD足夠普及,以多線程方式執行I/O可能會很有效。 – 2012-02-07 12:21:56

回答

2

您可以使用mmap。請參閱mmap() vs. reading blocks

正如Tim Cooper指出的那樣,當您有隨機訪問權限(多線程會使您看起來像您擁有這個)時,mmap是一個好主意,並且他們可以共享相同的物理頁面。

+0

這似乎很棒!我查看了mmap的python文檔,但找不到有關線程安全性的參考。如果2個線程同時執行類似a = mappedfile [x:y]的操作,它是否會按預期工作? – Alberto 2012-02-07 13:47:37

+0

爲了回答我自己,看起來python mmap切片符號實際上是線程安全的。我創建了一個測試程序,用於從不同線程訪問mmapped文件的不同部分,並檢查結果。如果我使用切片符號,它會通過測試,如果我使用seek/read,則失敗。不過,我仍然需要檢查性能。 – Alberto 2012-02-07 16:30:25

+1

@Alberto:在我看來,任何已經被處理的給定段應該至少由一個互斥量保護,如果不是一個有條件的信號量拋出。通過拋出有條件的信號量,我的意思是一個信號量不會等待直到它出現時纔會滿足事件前條件,而是拋出異常。它是一個信號量和gaurd之間的混合體。您可能只想在條件B不滿足時拋出,如果滿足條件A則等待。 – 2012-02-07 19:33:56

2

你可能想,如果你不這樣做,已經使用Leader/Follower模式。
Leader線程將知道哪些段已被處理,哪些不處理,並將自身分配給下一個未處理的段,然後成爲跟隨者,將領導留在池中的下一個可用線程。

+0

謝謝,我會考慮這一點。 – Alberto 2012-02-07 12:29:51

1

CPython有GIL,因此多個線程不會提高CPU綁定任務的性能。

如果問題不是IO限制(磁盤提供/存儲數據比CPU更快解壓縮),則可以使用multiprocessing module:每個進程打開文件並解壓縮給定的字節範圍。

+1

主解壓縮函數是一個C擴展,它調用Py_ALLOW_THREADS,以便在解壓縮時釋放GIL。第二階段減壓使用numpy也是無gil的。我已經測量了一個很好的加速。 – Alberto 2012-02-07 13:32:17

+0

(也許這個澄清 - 關於你有「照顧」的GIL - 也可以進入問題主體) – jsbueno 2012-02-07 15:43:07

+0

10你是對的,完成 – Alberto 2012-02-07 16:25:25