Domanda

Vorrei fare una domanda a seguire una mia risposta, ma anche di vedere quali risposte hanno le altre persone.

Ci sono due file di grandi dimensioni che ci piacerebbe leggere da due thread separati contemporaneamente.Un thread leggere in modo sequenziale fileA, mentre l'altro thread di leggere in modo sequenziale fileB.Non c'è nessun blocco o la comunicazione tra thread, sia in modo sequenziale lettura come veloce come si può, ed entrambi sono immediatamente scartare i dati di lettura.

La nostra esperienza con questo tipo di configurazione su Windows è molto scarsa.Il combinato throughput dei due thread è dell'ordine di 2-3 MiB/sec.L'auto sembra di trascorrere la maggior parte del suo tempo alla ricerca di avanti e indietro tra i due file, presumibilmente lettura poco dopo ogni ricerca.

Se si disattiva uno dei thread e temporaneamente guardare le prestazioni di un singolo thread si ottiene quindi molto meglio la larghezza di banda (~45 MiB/sec per questa macchina).Quindi è chiaro che il male a due filetti di prestazioni è un artefatto del sistema operativo disco di pianificazione.

C'è qualcosa che possiamo fare per migliorare il concorrente thread prestazioni di lettura? Forse utilizzando diverse Api o modificando il sistema operativo del disco di pianificazione parametri in qualche modo.

Alcuni dettagli:

I file sono in ordine di 2 Gb ciascuno su una macchina con 2 gib di RAM.Per lo scopo di questa domanda noi riteniamo non essere memorizzato nella cache e perfettamente deframmentato.Abbiamo utilizzato strumenti di deframmentazione e riavviato per garantire questo è il caso.

Stiamo utilizzando speciali di Api per leggere questi file.Il comportamento è ripetibile tra i vari bog-standard Api come Win32 della CreateFile, C fopen, C++s'std::ifstream, FileInputStream Java, etc.

Ogni thread giri in un ciclo di effettuare le chiamate alla funzione di lettura.Abbiamo variato il numero di byte richiesti dalle API ogni iterazione il valore tra 1KiB fino a 128MiB.Variando questo non ha avuto alcun effetto, così chiaramente l'importo che l'OS non è fisicamente in lettura dopo ogni ricerca su disco non è dettato da questo numero.Questo è esattamente quello che dovrebbe essere previsto.

La differenza sostanziale tra un filo e due filetti di prestazioni è ripetibile tra Windows 2000, Windows XP (32-bit e 64-bit), Windows Server 2003, e anche con e senza hardware RAID5.

È stato utile?

Soluzione

Il problema sembra essere in I/O di Windows politica di programmazione.Secondo quello che ho trovato qui ci sono molti modi per un O. S.per pianificare richieste del disco.Mentre Linux e altri possono scegliere tra le diverse politiche, a prima Vista, Windows è stato bloccato in un unico criterio:una coda FIFO, dove tutte le richieste in cui è diviso in 64 KB blocchi.Credo che questa politica è la causa del problema:la pianificazione mix richieste dai due fili, causando un continuo cercare tra le diverse aree del disco.
Ora, la buona notizia è che, secondo qui e qui, Vista ha introdotto un più intelligente disco di pianificazione, in cui è possibile impostare la priorità delle richieste e assegna un minimo badwidth per il vostro processo.
La cattiva notizia è che ho trovato nessun modo per cambiare il disco o la politica di buffer di dimensione nelle versioni precedenti di Windows.Inoltre, anche se alzando I/O del disco priorità del processo di incrementare le prestazioni contro gli altri processi, hai ancora i problemi del tuo thread in competizione contro gli altri.
Quello che posso suggerire è quello di modificare il software, introducendo un self-made disco criteri di accesso.
Per esempio, si potrebbe utilizzare un criterio come questo nel vostro thread B (simile per il Thread):

if THREAD A is reading from disk then wait for THREAD A to stop reading or wait for X ms
Read for X ms (or Y MB)
Stop reading and check status of thread A again  

Si potrebbe utilizzare semafori per verificare il proprio stato o si potrebbe utilizzare perfmon counters per ottenere lo stato del disco effettivo coda.I valori di X e/o Y potrebbe anche essere auto-tune verificando l'effettivo trasferimento dei tassi e, lentamente, modificarli, in modo da massimizzare la produttività quando l'applicazione viene eseguita su macchine diverse e/o O. S.Si potrebbe trovare che la cache, la memoria o i livelli di RAID li riguardano in un modo o nell'altro, ma con l'auto-tuning sarà sempre ottenere le migliori prestazioni in ogni scenario.

Altri suggerimenti

Vorrei aggiungere alcune ulteriori note nella mia risposta.Tutti gli altri non-Microsoft sistemi operativi che abbiamo testato non soffrono di questo problema.Linux, FreeBSD e Mac OS X (quest'ultimo su hardware diverso) tutti si degradano molto più elegantemente in termini di larghezza di banda aggregata quando si spostano da un thread a due.Linux per esempio degradati da ~45 MiB/sec ~42 MiB/sec.Questi altri sistemi operativi deve essere la lettura di grandi blocchi di file tra cercare, e quindi non spendendo quasi tutto il loro tempo in attesa del disco per cercare.

La nostra soluzione per Windows è quello di superare il FILE_FLAG_NO_BUFFERING bandiera a CreateFile e l'uso di grandi dimensioni (~16MiB) legge ogni chiamata ReadFile.Questo è ottimale per diversi motivi:

  • I file non si ottiene quando la cache di lettura come questa, quindi non ci sono nessuno dei vantaggi che la cache normalmente dà.
  • I vincoli quando si lavora con questa bandiera sono molto più complicate rispetto al normale lettura (allineamento di leggere il buffer per i limiti della pagina, ecc).

(Come osservazione finale.Questo spiega perché lo swapping sotto Windows è così infernale?Ie, Windows è in grado di fare IO a più file contemporaneamente con la sua efficienza, così durante lo scambio di tutte le altre operazioni di i / o sono costretti a essere molto più lento).


Edit per aggiungere ulteriori dettagli per Dean:

Naturalmente, al di là di queste diverse configurazioni hardware raw figure ha fatto cambiare (a volte in modo sostanziale).Il problema, tuttavia, è il costante degrado delle prestazioni che solo Windows soffre quando si spostano da un thread a due.Ecco una sintesi delle macchine testate:

  • Più Dell workstation (Intel Xeon), di diverse età, che esegue Windows 2000, Windows XP (32-bit) e Windows XP (64-bit) con una singola unità.
  • Dell 1U server (Intel Xeon) che esegue Windows Server 2003 (64-bit) con il RAID 1+0.
  • Una workstation HP (AMD Opteron) con Windows XP (64-bit) e Windows Server 2003, e RAID 5 hardware.
  • La mia casa sprovvista di PC (AMD Athlon64) che esegue Windows XP (32-bit), FreeBSD (64-bit), Linux (64-bit) con una singola unità.
  • La mia casa MacBook (Intel Core1) in esecuzione Mac OS X, singolo disco SATA.
  • La mia casa Koolu PC con Linux.Sottopotenziati rispetto ad altri sistemi, ma ho dimostrato che anche questa macchina in grado di superare un server Windows con RAID5 quando si fa multi-threaded letture del disco.

L'utilizzo della CPU su tutti questi sistemi era molto bassa durante le prove e anti-virus è stato disattivato.

Ho dimenticato di dire prima, ma abbiamo provato anche la normale Win32 CreateFile API con il FILE_FLAG_SEQUENTIAL_SCAN set di bandiere.Questo flag non risolvere il problema.

Sembra un po ' strano che si vede alcuna differenza tra una gamma abbastanza vasta di versioni di windows e non c'è nulla tra una singola unità e hardware raid-5.

È solo 'istintiva', ma che non mi fanno dubitare che questo è in realtà una semplice ricerca di problema.Diverso da OS X e il Raid5, era tutto questo provato sulla stessa macchina - hai provato con un'altra macchina?È l'utilizzo della CPU praticamente a zero durante questo test?

Qual è il minor app si può scrivere che dimostra questo problema?- Sarei interessato a provare qui.

Vorrei creare una sorta di memoria thread-safe lock.Ogni thread può aspettare il blocco fino a quando non è libero.Quando il blocco diventa libero, prendere il blocco e leggere il file per un determinato periodo di tempo o per una determinata quantità di dati, quindi rilasciare il blocco per qualsiasi altro thread in attesa.

Si usa IOCompletionPorts sotto Windows?Windows tramite il C++ è un approfondito capitolo su questo argomento e come la fortuna, è anche disponibile su MSDN.

Paolo - visto l'aggiornamento.Molto interessante.

Sarebbe interessante provarlo su Vista o Win2008, come persone sembrano essere un resoconto di alcune notevoli I/O miglioramenti su questi in alcune circostanze.

Il mio unico suggerimento su un diverso API sarebbe provare la mappatura della memoria il file - hai provato?Purtroppo a 2GB per file, non avete intenzione di essere in grado di associare più tutto il file su una macchina a 32-bit, il che significa che questo non è così banale come potrebbe essere.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top