我有一個python
腳本,它可以在以下方案中工作:讀取一個大文件(例如電影) - 將選定的信息組合成一些小的臨時文件 - 在子進程中產生一個C++
應用程序執行文件處理/計算(分別爲每個文件) - 讀取應用程序輸出。爲了加速我使用多處理的腳本。但是,它有一個主要缺點:每個進程必須在RAM中保留大型輸入文件的整個副本,因此我只能運行很少的進程,因爲內存不足。因此,我決定嘗試使用多線程(或多處理和多線程的某種組合),因爲線程共享地址空間。由於python
部分大部分時間都適用於文件I/O
或等待C++
應用程序完成,因此我認爲GIL
在這裏一定不是問題。儘管如此,我並未看到業績有所增長,主要歸功於I/O
部分。python中的多線程I/O放緩
我說明用下面的代碼(保存爲test.py
)的問題:
import sys, threading, tempfile, time
nthreads = int(sys.argv[1])
class IOThread (threading.Thread):
def __init__(self, thread_id, obj):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.obj = obj
def run(self):
run_io(self.thread_id, self.obj)
def gen_object(nlines):
obj = []
for i in range(nlines):
obj.append(str(i) + '\n')
return obj
def run_io(thread_id, obj):
ntasks = 100 // nthreads + (1 if thread_id < 100 % nthreads else 0)
for i in range(ntasks):
tmpfile = tempfile.NamedTemporaryFile('w+')
with open(tmpfile.name, 'w') as ofile:
for elem in obj:
ofile.write(elem)
with open(tmpfile.name, 'r') as ifile:
content = ifile.readlines()
tmpfile.close()
obj = gen_object(100000)
starttime = time.time()
threads = []
for thread_id in range(nthreads):
threads.append(IOThread(thread_id, obj))
threads[thread_id].start()
for thread in threads:
thread.join()
runtime = time.time() - starttime
print('Runtime: {:.2f} s'.format(runtime))
當我與不同數量的線程運行它,我得到這個:
$ python3 test.py 1
Runtime: 2.84 s
$ python3 test.py 1
Runtime: 2.77 s
$ python3 test.py 1
Runtime: 3.34 s
$ python3 test.py 2
Runtime: 6.54 s
$ python3 test.py 2
Runtime: 6.76 s
$ python3 test.py 2
Runtime: 6.33 s
能有人給我解釋一下結果,以及給出一些建議,如何有效地使用多線程並行I/O
?
編輯:
放緩並不是由於硬盤的性能,這是因爲:
1)中的文件越來越緩存反正到RAM
2)多相同的操作(不多線程)確實變得越來越快(幾乎是CPU數量的因素)
阿里納斯 - 我總是喜歡用'multiprocessing'和'multiprocessing.dummy'輕鬆測試多處理與多線程問題。它提供了一個簡單的API和流程和線程之間的無障礙切換。 – arvindch
你有沒有考慮過使用內存映射?這將映射文件到內存中,但在進程之間共享。然後操作系統將在必要時執行實際的IO。當它不再被使用時它也將釋放RAM,即它不交換。 –