{"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\/it\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","title":{"rendered":"Accelerazione dell'input\/output dei file C\/C++, senza troppa fatica","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Accelerazione dell&#039;input\/output dei file C\/C++, senza troppa fatica\" src=\"\/wp-content\/uploads\/2019\/03\/ed7e4c2b671c87b382572f08a411e009.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h4>Introduzione<\/h4>\n<p>\nEsiste nel mondo un'utile e semplice utilit\u00e0 \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/jjwhitney\/BDelta\">BDelta<\/a><\/noindex>, e cos\u00ec \u00e8 accaduto che si \u00e8 radicata nel nostro processo produttivo da molto tempo (anche se non sono riuscito a installare la sua versione, era sicuramente precedente all'ultima disponibile). La utilizziamo per il suo scopo principale \u2014 la creazione di patch binari. Se si guarda cosa c'\u00e8 nel repository, diventa un po' triste: in sostanza \u00e8 stato abbandonato da tempo e molte cose sono diventate obsolete (una volta il mio ex-collega ha fatto alcune modifiche, ma \u00e8 passato molto tempo). In generale, ho deciso di riportarla in vita: ho fatto un fork, ho eliminato ci\u00f2 che non intendo usare, ho trasferito il progetto su <noindex><a rel=\"nofollow\" href=\"https:\/\/cmake.org\/\">cmake<\/a><\/noindex>, ho inlined le microfunzioni \u201ccalde\u201d, ho rimosso grandi array dallo stack (e array di lunghezza variabile, che onestamente mi danno fastidio), ho fatto girare nuovamente il profiler \u2014 e ho scoperto che circa il 40% del tempo viene speso su <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>Cosa c'\u00e8 con fwrite?<\/h4>\n<p>\nNel codice attuale fwrite (nel mio specifico caso: creazione di un patch tra file da quasi 300 MB, i dati di input sono completamente in memoria) viene chiamato milioni di volte con un buffer di piccole dimensioni. \u00c8 evidente che questa cosa sar\u00e0 lenta, e quindi vorrei trovare un modo per influenzare questo problema senza complicazioni. Non ho voglia di implementare fonti di dati di vario genere o input\/output asincroni, volevo trovare una soluzione pi\u00f9 semplice. La prima cosa che mi \u00e8 venuta in mente \u00e8 stata aumentare la dimensione del buffer<\/p>\n<pre><code class=\"cpp\">setvbuf(file, nullptr, _IOFBF, 64* 1024)<\/code><\/pre>\n<p>\nma non ho ottenuto un miglioramento significativo (ora fwrite richiedeva circa il 37% del tempo) \u2014 significa che il problema non \u00e8 nella scrittura frequente dei dati su disco. Guardando \u201csotto il cofano\u201d di fwrite si pu\u00f2 vedere che all\u2019interno avviene un lock\/unlock della struttura FILE pi\u00f9 o meno cos\u00ec (pseudocodice, tutta l'analisi \u00e8 stata effettuata con 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);   \n   __try\n   {\n      retval = _fwrite_nolock(buffer, size, count, stream);\n   }\n   __finally \n   {\n       _unlock_str(stream);   \n   }\n   return retval;\n}\n<\/code><\/pre>\n<p>\nSe si crede al profiler, solo il 6% del tempo viene speso su _fwrite_nolock, il resto \u00e8 overhead. Nel mio caso specifico la sicurezza del thread \u00e8 un chiaro superfluo, e far\u00f2 a meno di essa, sostituendo la chiamata a fwrite con <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 non c'\u00e8 bisogno di complicare le cose nemmeno con argomenti. In sintesi: questa semplice manipolazione ha ridotto drasticamente i costi di registrazione del risultato, che nella versione originale costituivano quasi la met\u00e0 del tempo speso. A proposito, nel mondo POSIX esiste una funzione analoga \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/linux.die.net\/man\/3\/fwrite_unlocked\">fwrite_unlocked<\/a><\/noindex>. In effetti, lo stesso vale per fread. Cos\u00ec, con un paio di #define, \u00e8 possibile ottenere una soluzione abbastanza cross-platform senza blocchi superflui nel caso in cui non siano necessari (ed \u00e8 una situazione abbastanza comune).<\/p>\n<h4>fwrite, _fwrite_nolock, setvbuf<\/h4>\n<p>\nAsturiamo dall'originale e occupiamoci del test di un caso specifico: registrazione di un grande file (512 MB) in porzioni estremamente piccole \u2014 1 byte. Sistema di prova: AMD Ryzen 7 1700, 16 GB di RAM, HDD 7200 rpm con 64 MB di cache, Windows 10 1809, binario costruito a 32 bit, ottimizzazioni abilitate, libreria collegata staticamente.<\/p>\n<p>Esempio per eseguire l'esperimento:<\/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>\nCome variabili utilizzeremo TEST_BUFFER_SIZE e per un paio di casi sostituiremo fwrite_unlocked con fwrite. Iniziamo con il caso di fwrite senza un'impostazione esplicita della dimensione del buffer (commentiamo setvbuf e il codice correlato): tempo 27048906 \u00b5s, velocit\u00e0 di scrittura \u2014 18.93 MB\/s. Ora impostiamo la dimensione del buffer a 64 KB: tempo \u2014 25037111 \u00b5s, velocit\u00e0 \u2014 20.44 MB\/s. Ora testeremo il funzionamento di _fwrite_nolock senza chiamare setvbuf: 7262221 \u00b5s, velocit\u00e0 \u2014 70.5 MB\/s! <\/p>\n<p>Procediamo quindi a sperimentare con la dimensione del buffer (setvbuf):<\/p>\n<p><img decoding=\"async\" alt=\"Accelerazione dell&#039;input\/output dei file C\/C++, senza troppa fatica\" src=\"\/wp-content\/uploads\/2019\/03\/6d7998d805ec2e3f0a7905251c664e5c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nI dati sono stati ottenuti come media di 5 esperimenti, non mi sono preso la briga di calcolare gli errori. A mio avviso, 93 MB\/s durante la scrittura di 1 byte su un normale HDD \u00e8 un risultato davvero buono, basta semplicemente scegliere la dimensione del buffer ottimale (nel mio caso 256 KB \u00e8 perfetto) e sostituire fwrite con _fwrite_nolock\/fwrite_unlocked (nel caso in cui la sicurezza dei thread non sia necessaria, ovviamente). <br \/>\nAnalogamente per fread in condizioni simili. Poich\u00e9 non ho una macchina 'reale' con linux a disposizione (i single board non contano), ho deciso di condurre un esperimento limitato su una macchina virtuale (Hyper-V, OpenSUSE 15, GCC 8.3.1) \u2014 la regola \u00e8 sostanzialmente la stessa: fwrite 'puro' 20 MB\/s, fwrite + buffer di 256 KB ha reso 23 MB\/s, fwrite_unlocked con lo stesso buffer \u2014 35 MB\/s (binario a 64 bit, compilato con g++ -o2 -s -static-libgcc -static-libstdc++ fwrite_test.cpp -o fwrite_test).<\/p>\n<h4>Postfazione<\/h4>\n<p>\nL'obiettivo di questo articolo era descrivere un metodo semplice ed efficace che funziona in molti casi (non avevo mai incontrato le funzioni _fwrite_nolock\/fwrite_unlocked, non sono molto popolari \u2014 e sarebbe un peccato). Non pretendo di portare novit\u00e0, ma spero che l'articolo si riveli utile alla comunit\u00e0.<\/p>\n<p>Fonte: <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.1.1 - 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\/it\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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\udd47Accelerazione dell'input\/output di file C\/C++, senza troppi sforzi | ProHoster","description":"Prefazione","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/42134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=42134"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/42134\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=42134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=42134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=42134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}