7
votes

Win32 API FindFirstFile et FindNextFile Performances VS Ligne de commande

Nous avons rencontré un problème de performance inattendu lors de la traversée des répertoires à la recherche de fichiers à l'aide d'un modèle Wildcard.

Nous avons 180 dossiers chacun contenant 10 000 fichiers. Une recherche de ligne de commande en utilisant dir / s termine presque instantanément (<0,25 seconde). Cependant, à partir de notre application, la même recherche prend entre 3 et 4 secondes.

Nous avons d'abord essayé d'utiliser system.io.directoryinfo.idio.directoryinfo.gefiles () avec searchOption.Alldirectories et ont maintenant essayé les appels d'API Win32 FindFirstFile () et FindNextFile () .

Profilage de notre code en utilisant indique que la grande majorité du temps d'exécution est dépensé pour ces appels.

Notre code est basé sur le blog suivant:

http://codebetter.com/blogs/matthew.podwysocki/archive/2008/10/16/fonctionnel-net-fighting-friction-in-the-bcl-with-Directory-gefiles. ASPX

Nous avons trouvé que ceci soit lent, ce qui est mis à jour la fonction getfiles pour prendre un chaîne modèle de recherche plutôt qu'un prédicat.

Quelqu'un peut-il perdre une lumière sur ce qui pourrait se tromper avec notre approche?


7 commentaires

Qu'est-ce que vous utilisez pour effectuer la recherche de la ligne de commande? Pourrait-il être qu'il utilise les index de recherche Windows pour effectuer la requête plutôt que de progresser dans chaque fichier?


@Matt nous venons de faire un dir / s (avez mis à jour mon message en conséquence).


Semble suspect. Je doublis sérieusement que "Dir" utilise autre chose, à l'exception de FindFirstFile / FindNextFile. Peut-être que vous les abusez. Pourriez-vous fournir un extrait d'illustrer comment vous les utilisez?


@shachartooth: J'ai ajouté un lien vers un message contenant le code source que nous avons utilisé.


@Matt Dir n'utilise pas de service d'index


@Shengjiang 蒋晟 fait Directory.getFiles Méthode utilise le service d'index? Comment puis-je savoir ça?


Comparez avec ShellseearchFolder dans Windows API Code Pack et vous le saurez.


3 Réponses :


3
votes

Vous pouvez essayer avec une implémentation de FindFirstFile et FindNextFile i une fois blogué à propos de.


4 commentaires

Notre approche est très similaire à celle de ce Darin


J'ai testé ma solution et il faut 230 millisecondes pour énumérer un répertoire contenant> 100K fichiers.


Une nouvelle vitesse peut être obtenue avec FindFirstFileEx (... FindexInfobasic ...)


Dans notre scénario, nous avons 180 dossiers, chacun contenant environ 10 000 fichiers. La scission sur plusieurs dossiers est ce qui semble tuer la performance.



0
votes

ESSAYER ISHELLFOLDER :: EnumObjects avec ShgetDataFromIDList / IShellfolder :: getattributes de .

pro / contre ici .


0 commentaires

11
votes

dans mes tests à l'aide de FindFirstFileEx avec FindexInfobasic et Find_First_ex_large_fetch est beaucoup plus rapide que le fichier FindFiStfile .

Numérisation 20 dossiers avec ~ 300 000 fichiers ont pris 661 secondes avec FindFirstFile FindFirstFileEx . Les appels ultérieurs vers les mêmes dossiers ont pris moins d'une seconde. xxx


3 commentaires

Sous Windows 7 x64 la différence entre utiliser Find_First_ex_large_fetch et non est 0x10000 par rapport à 0x1000 octets pour le tampon de recherche (trouvé avec IDA). FindexInfobasic peut être plus pertinent ici, cependant.


Mes mesures (W10 X64, SSD Disk Drive) montrent que FindFirstFileEx est marginalement (~ 14%) plus rapide que FindFirstFile. Le dossier de test avait des fichiers de 900k. Les énumérations ont pris typiquement 1,5 seconde. Sauf la toute première énumération, lorsque l'énumération prend 10 fois plus longtemps. (Pour les deux méthodes, bien sûr.)


Doivent me corriger en ce qui concerne la toute première énumération. Après de nombreux tests de référence, je peux confirmer que la première énumération (après avoir effacé le cache de disque) est a) ~ 3x plus lente dans le cas de FindFirstFileEx () (... FindexInfobasic, ... Find_First_ex_large_fetch), B) ~ 20x plus lent en cas de FindFirstFile ().