2009-09-24 76 views
3

我需要在Linux下使用多個線程讀取單個文件。 只有閱讀操作,不需要書寫。 文件讀取不需要每次讀取整個文件。 它需要每次讀取文件的一個或多個部分。 我預先存儲了每個部分的偏移量。 該文件太大而無法放入主內存。如何提高多線程文件讀取的性能?

因此,例如,許多用戶想讀取這樣的文件。 我使用線程或進程來讀取文件以回答用戶請求。 在Linux下會發生什麼? 所有的讀取操作都會排隊嗎? 操作系統會一一完成文件讀取? 是否有可能提高這些操作的性能?

我想實現一個簡單的倒排索引用於信息檢索。 我把字典放在內存中,並在文件中發佈列表。 每個文件都包含一段索引。 在字典中,我可以存儲偏移量等指向該單詞發佈列表的位置。 當100個用戶想要在一秒鐘內搜索某些內容時,他們會提交不同的查詢。 因此每個閱讀將會讀取文件的不同部分。

+0

的是我說錯了,當我問緩存未命中。文件閱讀不需要每次都讀取整個文件。它需要每次讀取文件的一個或多個部分。我事先存儲每個部分的偏移量。 – 2009-09-24 07:59:55

回答

0

如果文件太大而無法放入系統內存,並且您有大量線程需要讀取整個文件,則很可能您的應用程序將受磁盤I/O限制。無論你如何閱讀文件,無論操作系統多麼聰明。

如果這是不可接受的,那麼您需要爲您的應用程序提供一個替代架構。例如,您可能會將該文件轉換爲不同的表單,以便線程可以在不讀取整個文件的情況下獲取他們所需的信息。或者你可以將應用程序轉換爲單獨的進程,運行在不同的機器上,每一個都有自己的文件副本。第三種可能性是添加一個線程,其唯一目的是讀取和緩衝文件,並從緩衝區讀取現有線程。 (通過讓工作線程全部工作在文件的相同區域,可以避免操作系統多次從磁盤讀取文件的某些部分,如果應用程序真的是磁盤綁定的,這可能會加快速度。)

然而,所有這些都是猜想。沒有關於應用程序和它處理的文件的更多信息,很難給出體面的建議。

編輯:根據您的後續評論,似乎線程並不需要訪問所有的文件。我的第一個建議是沒有意義的(你已經準備好這麼做了!),而我的第三個建議也無濟於事。我建議你像@Jon Skeet所說的那樣以簡單的方式實現這個系統。那麼如果存在性能問題,尋找使其更快/更好的方法。例如:

  • 考慮實施最近查詢的內存緩存及其結果。
  • 考慮使用多臺機器,並通過關鍵字範圍對索引文件進行分區,以便每個部分都可以放入一臺機器的內存中。
  • 如果您支持複雜查詢,請考慮將它們拆分爲簡單查詢並將簡單查詢發送到不同的機器(例如,基於關鍵字分區),然後組合結果集。
  • 考慮避免在用戶只想查看前幾個結果時計算巨大結果集的方法。

我幾年前從一位同事那裏借用了一本關於索引的有趣教科書。我認爲這是Managing Gigabytes by Witten et al

+0

嗨,我更新了問題並解釋了我的申請。 – 2009-09-24 08:07:01

3

嘗試以最簡單的方式實現它 - 讓操作系統通過緩存等方式來處理它的效率。查看性能如何 - 它可能不會成爲瓶頸。操作系統一般都擅長這種事情:)

假設你能夠打開文件進行分享閱讀多次,我希望它做工精細,無需排隊所有的讀操作。

+6

快樂100k !!! :-) – 2009-09-24 07:29:39

1

操作系統通常非常擅長優化對文件的訪問(Linux以積極緩存而聞名)。但我認爲減少讀取量對於提高效率至關重要,您是否真的無法擺脫單個共享數據代表一個文件的結構?這樣一個單線程讀取,每個其他線程從閱讀中受益。由於它只是讀取數據,因此只有在數據結構被填充時纔會有數據結構的爭用。如果每個線程每次都讀取文件的不同部分,這當然是不可行的。由於你不能從緩存中獲益(很多),也不能共享文件的讀取部分,所以沒有太多的事情要做(只是讀取文件),而是爲了改進你的磁盤子系統:獲得大量快速磁盤吞吐量(RAID 10)。如果這還不夠,請在不同的邏輯驅動器上創建兩個或多個文件副本,以便能夠增加吞吐量。

+0

我試圖實現一個簡單的倒排索引用於信息檢索。我把字典放在內存中,並在文件中發佈列表。 每個文件都包含索引的分段。在字典中,我可以存儲偏移量等指向該單詞發佈列表的位置。當100個用戶想要搜索某些內容時,他們會提交不同的查詢。所以每次閱讀都會讀取文件的不同部分。你提到了緩存,但是如果字典使用大部分內存,如果文件很大,Linux緩存文件將如何。 – 2009-09-24 07:49:59

2

線程可以獨立安全地讀取文件,是的。最終,讀取操作將在操作系統級別排隊,因此驅動程序將讀取請求串行化到磁盤。根據訪問策略(即讀取緩衝區大小),讀取應該交錯。除非你嘗試在一個請求中讀取整個文件(你不應該這麼說,因爲你說它太大而不適合內存),那麼讀取請求將按照線程請求它們的順序進行處理。 (我大概說,因爲磁盤驅動程序可以重新排列它在隊列中知道的讀取請求以優化磁盤訪問)。所以你描述的應該可以正常工作。操作系統會盡可能地積極緩存讀取(和預加載)。

至於提高性能,取決於數據和使用的算法有很多可能性。每個線程真的需要讀取整個文件來處理每個請求嗎?爲什麼一遍又一遍讀取相同的數據?難道你不能集中一些信息,以便線程可以共享讀取的數據嗎?這聽起來很昂貴的解決方案。如果您反覆讀取大於RAM的文件,最近有可能重新讀取的緩存塊可能會被推出緩存。也許文件的索引可以節省一些讀取時間,並且基於索引緩存訪問?另外考慮使用mmap()將文件映射到內存中,然後當線程從不同的塊中讀取時,操作系統將頁面塊進入和退出。因此,值得重新思考如何訪問數據,正是您需要和時間。如果您在此發佈更多信息,用戶可能會提供更具體的建議。

請記住,最有效的操作是你不執行的操作!

+0

我問了一句,我說錯了。文件閱讀不需要每次都讀取整個文件。它需要每次讀取文件的一個或多個部分。我事先存儲每個部分的偏移量。 – 2009-09-24 07:55:33

+0

在這種情況下,您可以讓一個類負責讀取,並讓線程請求塊。它可以保持最近讀取的偏移量和高速緩存塊的索引。但首先,值得做一些分析,看看你需要優化的地方。即使是一個簡單的'strace'也可以讓你瞭解閱讀模式。 – gavinb 2009-09-24 08:28:49

2

你的文件有多大,它不會全部適合內存?

如果將文件映射到(虛擬)內存中,然後讓所有線程都通過內存訪問該文件,將會最有效的方法是打開o/s並使用mmap()。如果您使用的是32位計算機,則會將文件大小限制爲「4GB以下,但可能超過2GB」;如果你使用的是64位機器,除了磁盤空間之外,你並沒有真正受到限制。

請注意,該文件不需要全部位於物理內存mmap();然而,它將全部在那裏合乎邏輯。

+0

一個文件可以是2GB,但如果有10個這樣的文件怎麼樣?例如,只剩下2G空閒物理內存。 – 2009-09-24 07:58:35

+0

在32位機器上,你被窺探了。在64位機器上,o/s負責文件的分頁 - 線程正在使用的位將存儲在內存中,而不是位於磁盤上的位。 – 2009-09-24 08:29:02

0

點要注意

  • 有一個單一的驅動器,具有單個驅動
  • 而且有從多個線程

在這種情況下,由於下面的多個(隨機的)訪問你的多線程,東西是串行的(從驅動層)...所以,你可以做的最好的事情,

  • 提高你的進程的優先級(如果可能),從而使其他進程不要吃,佔用CPU時間
  • 分配線程之間的公平級調度
  • 基於訪問的隨機性(您可以啓用或禁用高速緩存)
    • 例如,您可以禁用緩存,如果閱讀是完全隨機的,你看,有大部分的時間