{"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\/de\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","title":{"rendered":"Beschleunigung von Dateiein- und -ausgabe in C\/C++, ohne sich besonders anzustrengen","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Beschleunigung von Dateiein- und -ausgabe in C\/C++, ohne sich besonders anzustrengen\" src=\"\/wp-content\/uploads\/2019\/03\/ed7e4c2b671c87b382572f08a411e009.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h4>Vorwort<\/h4>\n<p>\nEs gibt ein solches einfaches und sehr n\u00fctzliches Tool in der Welt \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/jjwhitney\/BDelta\">BDelta<\/a><\/noindex>, und es hat sich so ergeben, dass es schon lange in unserem Produktionsprozess verwurzelt ist (obwohl ich es nicht geschafft habe, die Version zu installieren, war sie definitiv nicht die neueste verf\u00fcgbare). Wir verwenden es f\u00fcr seinen urspr\u00fcnglichen Zweck \u2014 das Erstellen von bin\u00e4ren Patches. Wenn man sieht, was im Repository ist, wird es ein wenig traurig: Es ist im Wesentlichen seit langem aufgegeben worden und vieles dort ist stark veraltet (vor langer Zeit hat ein ehemaliger Kollege einige \u00c4nderungen vorgenommen, aber das ist lange her). Ich habe beschlossen, das Ganze wiederzubeleben: Ich habe geforkt, was ich nicht nutzen will, entfernt und das Projekt auf <noindex><a rel=\"nofollow\" href=\"https:\/\/cmake.org\/\">cmake<\/a><\/noindex>, \u201ehei\u00dfe\u201c Mikrofunktionen inline integriert, gro\u00dfe Arrays vom Stack entfernt (und Arrays variabler L\u00e4nge, die mir offen gesagt \u201eauf die Nerven gingen\u201c), den Profiler erneut durchlaufen lassen \u2014 und festgestellt, dass etwa 40 % der Zeit auf <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>verwendet werden. Was ist also mit fwrite?<\/h4>\n<p>\nIm vorliegenden Code wird fwrite (in meinem spezifischen Testfall: Patch-Erstellung zwischen nahen 300 MB Dateien, die Eingabedaten vollst\u00e4ndig im Speicher) millionenfach mit einem kleinen Puffer aufgerufen. Es ist offensichtlich, dass diese Angelegenheit verlangsamen wird, und deshalb wollte ich irgendwie Einfluss darauf nehmen, ohne allzu gro\u00dfe Umstellungen vorzunehmen. Quellen f\u00fcr Daten einf\u00fchren, asynchrone Ein- und Ausgabe ist momentan nicht gew\u00fcnscht; ich wollte eine einfachere L\u00f6sung finden. Das Erste, was mir einfiel, war, die Pufferspeichergr\u00f6\u00dfe zu erh\u00f6hen<\/p>\n<pre><code class=\"cpp\">setvbuf(file, nullptr, _IOFBF, 64* 1024)<\/code><\/pre>\n<p>\n, aber ich habe keine wesentliche Verbesserung des Ergebnisses erhalten (jetzt wurden etwa 37 % der Zeit auf fwrite verwendet) \u2014 das hei\u00dft, es liegt wohl nicht an der h\u00e4ufigen Schreibvorg\u00e4ngen auf die Festplatte. Ein Blick \u201eunter die Haube\u201c von fwrite zeigt, dass intern ungef\u00e4hr so etwas wie lock\/unlock der FILE-Struktur geschieht (Pseudocode, die gesamte Analyse erfolgte unter 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>\nWenn der Profiler zu glauben ist, entf\u00e4llt auf _fwrite_nolock lediglich 6 % der Zeit, der Rest ist Overhead. In meinem speziellen Fall ist Thread-Sicherheit ein offensichtlicher Luxus, den ich opfere, indem ich den Aufruf von fwrite durch <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 man muss nicht einmal mit Argumenten herumspielen. Insgesamt hat diese einfache Manipulation die Kosten f\u00fcr das Ergebnis erheblich reduziert, die im urspr\u00fcnglichen Fall fast die H\u00e4lfte der zeitlichen Aufwendungen ausmachten. \u00dcbrigens gibt es in der Welt von POSIX eine \u00e4hnliche Funktion \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/linux.die.net\/man\/3\/fwrite_unlocked\">fwrite_unlocked<\/a><\/noindex>. Grunds\u00e4tzlich gilt das Gleiche f\u00fcr fread. Somit kann man mit einem Paar #define eine v\u00f6llig plattform\u00fcbergreifende L\u00f6sung ohne unn\u00f6tige Sperren erhalten, sofern diese nicht notwendig sind (und das kommt ziemlich oft vor).<\/p>\n<h4>fwrite, _fwrite_nolock, setvbuf<\/h4>\n<p>\nLassen Sie uns von dem urspr\u00fcnglichen Projekt abstrahieren und einen spezifischen Fall testen: das Schreiben einer gro\u00dfen Datei (512 MB) in minimalen Portionen \u2014 jeweils 1 Byte. Testsystem: AMD Ryzen 7 1700, 16 GB RAM, HDD 7200 U\/min mit 64 MB Cache, Windows 10 1809, das Binary wurde 32-Bit kompiliert, Optimierungen sind aktiviert, die Bibliothek wurde statisch verlinkt.<\/p>\n<p>Beispiel f\u00fcr das Experiment:<\/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>\nAls Variablen werden TEST_BUFFER_SIZE verwendet, au\u00dferdem ersetzen wir in einigen F\u00e4llen fwrite_unlocked durch fwrite. Wir beginnen mit dem Fall fwrite ohne explizite Puffergr\u00f6\u00dfe (wir kommentieren setvbuf und den dazugeh\u00f6rigen Code aus): Zeit 27048906 \u00b5s, Schreibgeschwindigkeit \u2014 18,93 MB\/s. Jetzt setzen wir die Puffergr\u00f6\u00dfe auf 64 KB: Zeit \u2014 25037111 \u00b5s, Geschwindigkeit \u2014 20,44 MB\/s. Jetzt testen wir die Funktion _fwrite_nolock ohne Aufruf von setvbuf: 7262221 \u00b5s, Geschwindigkeit \u2014 70,5 MB\/s! <\/p>\n<p>Jetzt experimentieren wir mit der Puffergr\u00f6\u00dfe (setvbuf):<\/p>\n<p><img decoding=\"async\" alt=\"Beschleunigung von Dateiein- und -ausgabe in C\/C++, ohne sich besonders anzustrengen\" src=\"\/wp-content\/uploads\/2019\/03\/6d7998d805ec2e3f0a7905251c664e5c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDie Daten stammen aus dem Durchschnitt von 5 Experimenten, die Fehler zu berechnen, war mir zu m\u00fchsam. Meiner Meinung nach ist 93 MB\/s beim Schreiben von 1 Byte auf eine normale HDD ein sehr gutes Ergebnis; man muss lediglich die optimale Puffergr\u00f6\u00dfe w\u00e4hlen (in meinem Fall 256 KB \u2014 das ist genau richtig) und fwrite durch _fwrite_nolock\/fwrite_unlocked ersetzen (sofern keine Thread-Sicherheit erforderlich ist, versteht sich). <br \/>\n\u00c4hnlich verh\u00e4lt es sich mit fread unter \u00e4hnlichen Bedingungen. Da ich keinen \"hardwarem\u00e4\u00dfigen\" Rechner mit Linux zur Hand hatte (Einplatinencomputer z\u00e4hlen nicht), beschloss ich, ein begrenztes Experiment auf einer virtuellen Maschine (Hyper-V, OpenSUSE 15, GCC 8.3.1) durchzuf\u00fchren \u2014 die Regelm\u00e4\u00dfigkeit ist grunds\u00e4tzlich die gleiche: \u201enacktes\u201c fwrite 20 MB\/s, fwrite + Puffer von 256 KB gab 23 MB\/s, fwrite_unlocked mit demselben Puffer \u2014 35 MB\/s (Binary 64-Bit, kompiliert mit g++ -o2 -s -static-libgcc -static-libstdc++ fwrite_test.cpp -o fwrite_test).<\/p>\n<h4>Nachwort<\/h4>\n<p>\nZiel dieses Artikels war es, eine einfache und in vielen F\u00e4llen effektive Methode zu beschreiben (mit den Funktionen _fwrite_nolock\/fwrite_unlocked hatte ich vorher nie zu tun, sie sind nicht besonders beliebt \u2013 zu Unrecht). Ich erhebe keinen Anspruch auf Neuheit des Materials, hoffe jedoch, dass der Artikel der Gemeinschaft n\u00fctzlich sein wird.<\/p>\n<p>Quelle: <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\/de\/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=\"de_DE\" \/>\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\/de\/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\udd47Beschleunigung des Dateieingangs\/-ausgangs in C\/C++, ohne gro\u00dfen Aufwand | ProHoster","description":"Vorwort","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/uskorenie-fajlovogo-vvoda-vyvoda-c-c-ne-osobo-napryagayas","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","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\/de\/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\/de\/wp-json\/wp\/v2\/posts\/42134","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=42134"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/42134\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=42134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=42134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=42134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}