{"id":42134,"date":"2019-03-18T00:00:00","date_gmt":"2019-03-17T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas"},"modified":"2020-02-18T13:44:56","modified_gmt":"2020-02-18T10:44:56","slug":"uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","status":"publish","type":"post","link":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","title":{"rendered":"Aceleraci\u00f3n de entrada y salida de archivos en C\/C++, sin mucho esfuerzo","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Aceleraci\u00f3n de entrada y salida de archivos en C\/C++, sin mucho esfuerzo\" src=\"\/wp-content\/uploads\/2019\/03\/ed7e4c2b671c87b382572f08a411e009.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h4>Pr\u00f3logo<\/h4>\n<p>\nExiste en el mundo una herramienta tan simple y muy \u00fatil \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/jjwhitney\/BDelta\">BDelta<\/a><\/noindex>, y as\u00ed sucedi\u00f3 que se arraig\u00f3 en nuestro proceso de producci\u00f3n desde hace mucho tiempo (aunque no pude instalar su versi\u00f3n, estoy seguro de que no era la m\u00e1s reciente). La usamos para su prop\u00f3sito original: crear parches binarios. Al mirar lo que hay en el repositorio, se vuelve un poco triste: en esencia, ha estado abandonado durante mucho tiempo y muchas cosas all\u00ed est\u00e1n bastante desactualizadas (alguna vez mi ex compa\u00f1ero hizo algunas correcciones, pero eso fue hace tiempo). En resumen, decid\u00ed revivirlo: hice un fork, elimin\u00e9 lo que no planeo usar, y convert\u00ed el proyecto a <noindex><a rel=\"nofollow\" href=\"https:\/\/cmake.org\/\">cmake<\/a><\/noindex>, inline\u00e9 funciones micro 'calientes', elimin\u00e9 grandes arreglos de la pila (y arreglos de longitud variable, que realmente me molestan), ejecut\u00e9 el profiler una vez m\u00e1s \u2014 y descubr\u00ed que alrededor del 40% del tiempo se gastaba en <noindex><a rel=\"nofollow\" href=\"http:\/\/www.cplusplus.com\/reference\/cstdio\/fwrite\/\">fwrite<\/a><\/noindex>\u2026<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h4>\u00bfQu\u00e9 pasa con fwrite?<\/h4>\n<p>\nEn este c\u00f3digo, fwrite (en mi caso de prueba espec\u00edfico: crear un parche entre archivos de alrededor de 300 MB, con los datos de entrada completamente en memoria) se llama millones de veces con un buffer de peque\u00f1o tama\u00f1o. Es evidente que esta cosa va a ralentizarse, y por lo tanto quisiera influir en este desorden sin introducir diferentes fuentes de datos, ya que no tengo ganas de usar E\/S as\u00edncrono; quer\u00eda encontrar una soluci\u00f3n m\u00e1s sencilla. Lo primero que se me ocurri\u00f3 fue aumentar el tama\u00f1o del buffer<\/p>\n<pre><code class=\"cpp\">setvbuf(file, nullptr, _IOFBF, 64 * 1024)<\/code><\/pre>\n<p>\npero no obtuve una mejora sustancial en el resultado (ahora fwrite consum\u00eda alrededor del 37% del tiempo) \u2014 as\u00ed que el problema no est\u00e1 en la escritura frecuente de datos en el disco. Al mirar \u2018bajo el cap\u00f3\u2019 de fwrite, se puede ver que dentro ocurre un lock\/unlock de la estructura FILE aproximadamente as\u00ed (pseudoc\u00f3digo, todo el an\u00e1lisis se realiz\u00f3 en Visual Studio 2017):<\/p>\n<pre><code class=\"cpp\">\nsize_t fwrite (const void *buffer, size_t size, size_t count, FILE *stream)\n{\n   size_t retval = 0;\n   _lock_str(stream);   \/* lock stream *\/\n   __try\n   {\n      retval = _fwrite_nolock(buffer, size, count, stream);\n   }\n   __finally \n   {\n       _unlock_str(stream);   \/* unlock stream *\/\n   }\n   return retval;\n}\n<\/code><\/pre>\n<p>\nSi le creo al profiler, en _fwrite_nolock solo se gasta el 6% del tiempo, el resto es overhead. En mi caso espec\u00edfico, la seguridad de hilo es un exceso evidente, y me atrever\u00e9 a dejarla de lado, reemplazando la llamada a fwrite por <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/c-runtime-library\/reference\/fwrite-nolock?view=vs-2017\">_fwrite_nolock<\/a><\/noindex> \u2014 incluso con argumentos no hay que complicarse. En resumen: esta sencilla manipulaci\u00f3n redujo considerablemente los costos de grabaci\u00f3n del resultado, que en la variante original representaban casi la mitad del tiempo invertido. Por cierto, en el mundo POSIX existe una funci\u00f3n an\u00e1loga \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/linux.die.net\/man\/3\/fwrite_unlocked\">fwrite_unlocked<\/a><\/noindex>. En general, lo mismo aplica para fread. De este modo, con un par de #define se puede obtener una soluci\u00f3n multiplataforma sin bloqueos innecesarios en caso de que no sean necesarios (lo cual sucede con bastante frecuencia).<\/p>\n<h4>fwrite, _fwrite_nolock, setvbuf<\/h4>\n<p>\nAbstraig\u00e1monos del proyecto original y centr\u00e9monos en probar un caso espec\u00edfico: escribir un gran archivo (512 MB) en porciones extremadamente peque\u00f1as \u2014 de 1 byte. Sistema de prueba: AMD Ryzen 7 1700, 16 GB de RAM, HDD 7200 rpm con 64 MB de cach\u00e9, Windows 10 1809, el binario se compila en 32 bits, optimizaciones habilitadas, la biblioteca est\u00e1 vinculada est\u00e1ticamente.<\/p>\n<p>Muestra para realizar el experimento:<\/p>\n<pre><code class=\"cpp\">\n#include &lt;chrono&gt;\n#include &lt;cstdio&gt;\n#include &lt;inttypes.h&gt;\n#include &lt;memory&gt;\n\n#ifdef _MSC_VER\n#define fwrite_unlocked _fwrite_nolock\n#endif\n\nusing namespace std::chrono;\n\nint main()\n{\n    std::unique_ptr&lt;FILE, int(*)(FILE*)&gt; file(fopen(\"test.bin\", \"wb\"), fclose);\n    if (!file)\n        return 1;\n\n    constexpr size_t TEST_BUFFER_SIZE = 256 * 1024;\n    if (setvbuf(file.get(), nullptr, _IOFBF, TEST_BUFFER_SIZE) != 0)\n        return 2;\n\n    auto start = steady_clock::now();\n    const uint8_t b = 77;\n    constexpr size_t TEST_FILE_SIZE = 512 * 1024 * 1024;\n    for (size_t i = 0; i &lt; TEST_FILE_SIZE; ++i)\n        fwrite_unlocked(&amp;b, 1, sizeof(b), file.get());\n\n    auto end = steady_clock::now();\n    auto interval = duration_cast&lt;microseconds&gt;(end - start);\n    printf(\"Time: %lldn\", interval.count());\n\n    return 0;\n}\n<\/code><\/pre>\n<p>\nLas variables ser\u00e1n TEST_BUFFER_SIZE, y en un par de casos sustituiremos fwrite_unlocked por fwrite. Comencemos con el caso fwrite sin establecer expl\u00edcitamente el tama\u00f1o del b\u00fafer (comentaremos setvbuf y el c\u00f3digo relacionado): tiempo 27048906 \u00b5s, velocidad de escritura \u2014 18.93 MB\/s. Ahora establezcamos el tama\u00f1o del b\u00fafer en 64 KB: tiempo \u2014 25037111 \u00b5s, velocidad \u2014 20.44 MB\/s. Ahora probemos el funcionamiento de _fwrite_nolock sin llamar a setvbuf: 7262221 \u00b5s, velocidad \u2014 70.5 MB\/s! <\/p>\n<p>A continuaci\u00f3n, experimentaremos con el tama\u00f1o del b\u00fafer (setvbuf):<\/p>\n<p><img decoding=\"async\" alt=\"Aceleraci\u00f3n de entrada y salida de archivos en C\/C++, sin mucho esfuerzo\" src=\"\/wp-content\/uploads\/2019\/03\/6d7998d805ec2e3f0a7905251c664e5c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLos datos se obtuvieron promediando 5 experimentos, no me molest\u00e9 en calcular las desviaciones. En mi opini\u00f3n, 93 MB\/s al escribir de 1 byte en un HDD normal \u2014 es un resultado muy bueno, s\u00f3lo se necesita elegir el tama\u00f1o \u00f3ptimo del b\u00fafer (en mi caso 256 KB \u2014 es ideal) y reemplazar fwrite por _fwrite_nolock\/fwrite_unlocked (en caso de que no se necesite la seguridad de hilo, por supuesto). <br \/>\nLo mismo con fread en condiciones similares. Como no tengo una m\u00e1quina f\u00edsica con Linux a mano (las de una sola placa no cuentan), decid\u00ed realizar un experimento limitado en una m\u00e1quina virtual (Hyper-V, OpenSUSE 15, GCC 8.3.1) \u2014 la tendencia, en principio, es la misma: fwrite 'desnudo' 20 MB\/s, fwrite + b\u00fafer de 256 KB dio 23 MB\/s, fwrite_unlocked con el mismo b\u00fafer \u2014 35 MB\/s (binario de 64 bits, se compil\u00f3 g++ -o2 -s -static-libgcc -static-libstdc++ fwrite_test.cpp -o fwrite_test).<\/p>\n<h4>P\u00f3scrito<\/h4>\n<p>\nEl objetivo de este art\u00edculo era describir un m\u00e9todo simple y eficaz en muchos casos (no hab\u00eda encontrado antes las funciones _fwrite_nolock\/fwrite_unlocked, que no son muy populares, y eso es una pena). No pretendo ser original en el material, pero espero que el art\u00edculo sea \u00fatil para la comunidad.<\/p>\n<p>Fuente: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/444036\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435 \u0415\u0441\u0442\u044c \u043d\u0430 \u0441\u0432\u0435\u0442\u0435 \u0442\u0430\u043a\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0438 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u2014 BDelta, \u0438 \u0442\u0430\u043a \u0432\u044b\u0448\u043b\u043e, \u0447\u0442\u043e \u043e\u043d\u0430 \u043e\u0447\u0435\u043d\u044c \u0434\u0430\u0432\u043d\u043e \u0443\u043a\u043e\u0440\u0435\u043d\u0438\u043b\u0430\u0441\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 (\u043f\u0440\u0430\u0432\u0434\u0430 \u0435\u0451 \u0432\u0435\u0440\u0441\u0438\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c, \u043d\u043e \u043e\u043d\u0430 \u0442\u043e\u0447\u043d\u043e \u0431\u044b\u043b\u0430 \u043d\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0439). \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0435\u0451 \u043f\u043e \u043f\u0440\u044f\u043c\u043e\u043c\u0443 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u2014 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u043f\u0430\u0442\u0447\u0435\u0439. \u0415\u0441\u043b\u0438 \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u0442\u0430\u043c \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u2014 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u043b\u0435\u0433\u043a\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-42134","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435 \u0415\u0441\u0442\u044c.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0433\u043e \u0432\u0432\u043e\u0434\u0430-\u0432\u044b\u0432\u043e\u0434\u0430 C\/C++, \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043d\u0430\u043f\u0440\u044f\u0433\u0430\u044f\u0441\u044c | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435 \u0415\u0441\u0442\u044c.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-03-17T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T10:44:56+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Aceleraci\u00f3n de entrada\/salida de archivos en C\/C++, sin mucho esfuerzo | ProHoster","description":"Prefacio.","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0433\u043e \u0432\u0432\u043e\u0434\u0430-\u0432\u044b\u0432\u043e\u0434\u0430 C\/C++, \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043d\u0430\u043f\u0440\u044f\u0433\u0430\u044f\u0441\u044c | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435 \u0415\u0441\u0442\u044c.","og:url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-03-17T21:00:00+00:00","article:modified_time":"2020-02-18T10:44:56+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"42134","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 07:22:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 00:05:22","updated":"2026-01-22 07:22:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/42134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=42134"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/42134\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=42134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=42134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=42134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}