{"id":100467,"date":"2026-01-22T18:42:01","date_gmt":"2026-01-22T17:42:01","guid":{"rendered":"https:\/\/dyb.fr\/?p=100467"},"modified":"2026-01-22T18:48:14","modified_gmt":"2026-01-22T17:48:14","slug":"pourquoi-os-scandir-est-nettement-plus-rapide-que-os-walk-en-python","status":"publish","type":"post","link":"https:\/\/dyb.eu\/blog\/pourquoi-os-scandir-est-nettement-plus-rapide-que-os-walk-en-python\/","title":{"rendered":"Pourquoi os.scandir() est nettement plus rapide que os.walk() en python ?"},"content":{"rendered":"<figure class=\"wp-block-post-featured-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1376\" height=\"768\" src=\"https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/os-walk-et-scandir-python.png\" class=\"attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" style=\"object-fit:cover;\" srcset=\"https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/os-walk-et-scandir-python.png 1376w, https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/os-walk-et-scandir-python-1280x714.png 1280w, https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/os-walk-et-scandir-python-980x547.png 980w, https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/os-walk-et-scandir-python-480x268.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) and (max-width: 1280px) 1280px, (min-width: 1281px) 1376px, 100vw\" \/><\/figure>\n\n\n<h3 class=\"wp-block-heading\">Retour d\u2019exp\u00e9rience sur un benchmark simple en environnement r\u00e9el<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Lorsqu\u2019on d\u00e9veloppe des outils de synchronisation, d\u2019indexation ou de traitement de fichiers (sauvegarde, scan de r\u00e9pertoires, etc.), le parcours r\u00e9cursif du syst\u00e8me de fichiers devient tr\u00e8s vite un <strong>point critique de performance<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Chez <strong>DYB<\/strong>, nous avons voulu comparer concr\u00e8tement deux approches courantes en Python :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>os.walk()<\/code> (m\u00e9thode historique, tr\u00e8s utilis\u00e9e)<\/li>\n\n\n\n<li><code>os.scandir()<\/code> (API plus r\u00e9cente et bas niveau)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019objectif : <strong>un benchmark simple, sans optimisation artificielle<\/strong>, ex\u00e9cut\u00e9 sur des dossiers r\u00e9els, avec quelques centaines \u00e0 plusieurs dizaines de milliers de fichiers.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Le benchmark<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Le test consiste \u00e0 :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>parcourir r\u00e9cursivement un dossier<\/li>\n\n\n\n<li>compter le nombre total de fichiers<\/li>\n\n\n\n<li>mesurer le temps d\u2019ex\u00e9cution<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">M\u00eame logique, m\u00eame machine, m\u00eame code m\u00e9tier.<br>La seule diff\u00e9rence : la m\u00e9thode de parcours.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">R\u00e9sultats observ\u00e9s<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Voici quelques extraits repr\u00e9sentatifs des tests r\u00e9alis\u00e9s :<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Nombre de fichiers<\/th><th><code>os.walk()<\/code><\/th><th><code>os.scandir()<\/code><\/th><\/tr><\/thead><tbody><tr><td>67 fichiers<\/td><td>0,036 s<\/td><td>0,019 s<\/td><\/tr><tr><td>195 fichiers<\/td><td>0,180 s<\/td><td>0,100 s<\/td><\/tr><tr><td>8 852 fichiers<\/td><td>10,28 s<\/td><td>5,54 s<\/td><\/tr><tr><td>19 381 fichiers<\/td><td>18,25 s<\/td><td>9,95 s<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udc49 <strong>Dans tous les cas, <code>os.scandir()<\/code> est environ 2\u00d7 plus rapide.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Et plus l\u2019arborescence est grande, plus l\u2019\u00e9cart devient significatif.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"488\" height=\"520\" src=\"https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/image.png\" alt=\"\" class=\"wp-image-100470\" srcset=\"https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/image.png 488w, https:\/\/dyb.eu\/blog\/wp-content\/uploads\/2026\/01\/image-480x511.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 488px, 100vw\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Pourquoi cette diff\u00e9rence ?<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Le co\u00fbt cach\u00e9 des <code>stat()<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>os.walk()<\/code> repose sur une abstraction plus haut niveau.<br>Lorsqu\u2019il parcourt les fichiers, Python effectue <strong>beaucoup d\u2019appels syst\u00e8me <code>stat()<\/code><\/strong> pour d\u00e9terminer si une entr\u00e9e est un fichier ou un dossier.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ces appels sont :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>co\u00fbteux sur disque<\/li>\n\n\n\n<li>encore plus lents sur des <strong>partages r\u00e9seau (SMB, NFS, NAS)<\/strong><\/li>\n\n\n\n<li>multipli\u00e9s par le nombre total d\u2019entr\u00e9es<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. <code>os.scandir()<\/code> travaille plus bas niveau<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>os.scandir()<\/code> utilise directement les informations retourn\u00e9es par le syst\u00e8me de fichiers (via <code>dirent<\/code> sous Linux).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">R\u00e9sultat :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>le type (fichier\/dossier) est souvent d\u00e9j\u00e0 connu<\/li>\n\n\n\n<li>pas besoin de <code>stat()<\/code> syst\u00e9matique<\/li>\n\n\n\n<li>beaucoup moins de passages kernel \u2194 userland<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">C\u2019est pr\u00e9cis\u00e9ment ce qui explique le <strong>gain massif de performance<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u201cMais <code>os.walk()<\/code> utilise d\u00e9j\u00e0 scandir, non ?\u201d<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Oui\u2026 <strong>en interne<\/strong>, depuis Python 3.5.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mais :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>os.walk()<\/code> reste une API g\u00e9n\u00e9raliste<\/li>\n\n\n\n<li>elle g\u00e9n\u00e8re des tuples complets (<code>root<\/code>, <code>dirs<\/code>, <code>files<\/code>)<\/li>\n\n\n\n<li>elle fait plus de travail que n\u00e9cessaire dans des cas simples<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udc49 Quand on veut <strong>juste parcourir vite<\/strong>, <code>os.scandir()<\/code> utilis\u00e9 directement reste imbattable.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Pourquoi choisir Python, malgr\u00e9 des performances inf\u00e9rieures \u00e0 certains langages ?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Il est largement admis que Python est, sur le plan strictement technique, plus lent que des langages compil\u00e9s comme C, C++ ou Rust. Cette r\u00e9alit\u00e9 ne constitue cependant pas un d\u00e9faut en soi, mais plut\u00f4t un <strong>compromis assum\u00e9<\/strong>. Le choix d\u2019un langage ne se limite jamais \u00e0 la seule performance brute : il implique des consid\u00e9rations de budget, de complexit\u00e9, de maintenabilit\u00e9 et de dette technique sur le long terme.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Python se distingue avant tout par sa <strong>simplicit\u00e9 de conception et de lecture<\/strong>. Un code plus clair r\u00e9duit le temps de d\u00e9veloppement, facilite les relectures, limite les erreurs et permet une mont\u00e9e en comp\u00e9tence plus rapide des \u00e9quipes. \u00c0 budget \u00e9gal, cela se traduit par plus de fonctionnalit\u00e9s livr\u00e9es, plus vite, et avec un risque projet nettement inf\u00e9rieur.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Par ailleurs, tous les projets ne n\u00e9cessitent pas une optimisation maximale d\u00e8s leur conception. Dans de nombreux cas, la performance n\u2019est pas le facteur limitant principal, ou peut \u00eatre am\u00e9lior\u00e9e ponctuellement, uniquement l\u00e0 o\u00f9 c\u2019est n\u00e9cessaire. Python permet pr\u00e9cis\u00e9ment cette approche progressive : commencer simple, puis optimiser de mani\u00e8re cibl\u00e9e, sans sur-ing\u00e9nierie pr\u00e9matur\u00e9e.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enfin, la dette technique est souvent sous-estim\u00e9e lorsqu\u2019on privil\u00e9gie des technologies plus complexes d\u00e8s le d\u00e9part. Des langages tr\u00e8s performants mais plus exigeants en expertise peuvent g\u00e9n\u00e9rer des co\u00fbts \u00e9lev\u00e9s en maintenance, en recrutement et en \u00e9volution fonctionnelle. Python, en r\u00e9duisant cette complexit\u00e9 initiale, offre un <strong>\u00e9quilibre durable<\/strong> entre efficacit\u00e9, \u00e9volutivit\u00e9 et ma\u00eetrise des co\u00fbts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bref, un peu d'amour pour Python \ud83d\ude09<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Cas concrets o\u00f9 la diff\u00e9rence est critique<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Chez DYB, ce genre de gain est loin d\u2019\u00eatre th\u00e9orique. Il est d\u00e9terminant pour :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udd04 <strong>outils de synchronisation<\/strong><\/li>\n\n\n\n<li>\ud83d\udcc2 <strong>scan de dossiers autonomes <\/strong>avec plusieurs dizaines de milliers de fichiers<\/li>\n\n\n\n<li>\ud83e\uddfe <strong>pipelines de traitement data<\/strong><\/li>\n\n\n\n<li>\ud83c\udf10 <strong>serveurs de fichiers<\/strong><\/li>\n\n\n\n<li>\ud83e\udde0 <strong>moteurs d\u2019indexation<\/strong><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Diviser par deux le temps de scan, c\u2019est :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>moins de charge CPU<\/li>\n\n\n\n<li>moins d\u2019I\/O disque<\/li>\n\n\n\n<li>moins de latence per\u00e7ue<\/li>\n\n\n\n<li>et une meilleure scalabilit\u00e9 globale<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Recommandation DYB<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udc49 <strong>Pour tout nouveau d\u00e9veloppement Python impliquant un parcours r\u00e9cursif de fichiers :<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>privil\u00e9gier <code>os.scandir()<\/code> avec une r\u00e9cursion explicite<\/li>\n\n\n\n<li>r\u00e9server <code>os.walk()<\/code> aux scripts simples ou non critiques<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Ce choix seul peut transformer un script \u201cacceptable\u201d en un outil <strong>r\u00e9ellement industriel<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Si vous travaillez sur des probl\u00e9matiques de <strong>performance, stockage, automatisation ou traitement de fichiers \u00e0 grande \u00e9chelle<\/strong>, DYB accompagne ses clients de l\u2019architecture jusqu\u2019\u00e0 l\u2019optimisation bas niveau.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udce9 <strong>Contactez-nous<\/strong> pour en discuter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Retour d\u2019exp\u00e9rience sur un benchmark simple en environnement r\u00e9el Lorsqu\u2019on d\u00e9veloppe des outils de synchronisation, d\u2019indexation ou de traitement de fichiers (sauvegarde, scan de r\u00e9pertoires, etc.), le parcours r\u00e9cursif du syst\u00e8me de fichiers devient tr\u00e8s vite un point critique de performance. Chez DYB, nous avons voulu comparer concr\u00e8tement deux approches courantes en Python : L\u2019objectif [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":100468,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[34],"tags":[33,32],"class_list":["post-100467","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev","tag-dev","tag-python"],"_links":{"self":[{"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/posts\/100467","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/comments?post=100467"}],"version-history":[{"count":2,"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/posts\/100467\/revisions"}],"predecessor-version":[{"id":100472,"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/posts\/100467\/revisions\/100472"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/media\/100468"}],"wp:attachment":[{"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/media?parent=100467"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/categories?post=100467"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dyb.eu\/blog\/wp-json\/wp\/v2\/tags?post=100467"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}