C/C++ فائل I/O کي تيز ڪريو بغير ڪنهن پسڻ جي

C/C++ فائل I/O کي تيز ڪريو بغير ڪنهن پسڻ جي

اڳوڻي

دنيا ۾ اهڙي هڪ سادي ۽ تمام مفيد افاديت آهي - بي ڊيلٽا، ۽ اهو ائين ٿيو آهي ته اهو اسان جي پيداوار جي عمل ۾ تمام گهڻي عرصي تائين جڙيل هو (جيتوڻيڪ اهو ان جو نسخو انسٽال ڪرڻ ممڪن نه هو، پر اهو يقيني طور تي آخري دستياب نه هو). اسان ان کي استعمال ڪريون ٿا ان جي گهربل مقصد لاءِ - عمارت بائنري پيچ. جيڪڏهن توهان ڏسو ته ذخيرو ۾ ڇا آهي، اهو ٿورو اداس ٿي وڃي ٿو: حقيقت ۾، اهو گهڻو وقت اڳ ڇڏي ويو هو ۽ ان جو گهڻو حصو تمام گهڻو پراڻو آهي (منهنجي اڳوڻي ساٿي هڪ ڀيرو اتي ڪيترائي ترميمون ڪيون، پر اهو گهڻو وقت اڳ هو) . عام طور تي، مون هن معاملي کي بحال ڪرڻ جو فيصلو ڪيو: مون ڪانٽو ڪيو، اڇلائي ڇڏيو جيڪو مون استعمال ڪرڻ جو ارادو نه ڪيو هو، منصوبي کي منتقل ڪيو ويو ڪيڪي, inlineed “hot” microfunctions، اسٽيڪ مان وڏيون صفون هٽائي ڇڏيون (۽ متغير ڊگھائي جون صفون، جيڪي صاف طور تي مون کي ”بم“ بڻائين ٿيون)، پروفائيل کي هڪ ڀيرو ٻيهر هلايو - ۽ معلوم ٿيو ته اٽڪل 40 سيڪڙو وقت خرچ ڪيو ويو آهي. لکڻ...

پوء fwrite سان ڇا ٿيو؟

هن ڪوڊ ۾، fwrite (منهنجي مخصوص ٽيسٽ ڪيس ۾: 300 ايم بي فائلن جي وچ ۾ پيچ ٺاهڻ، ان پٽ ڊيٽا مڪمل طور تي ميموري ۾ آهي) لکين ڀيرا سڏيو ويندو آهي ننڍڙي بفر سائيز سان. ظاهر آهي، اها شيء سست ٿي ويندي، ۽ تنهن ڪري مان چاهيان ٿو ته ڪنهن به طرح هن بي عزتي تي اثر انداز ٿئي. ڊيٽا ذريعن جي مختلف قسمن تي عمل ڪرڻ جي ڪا به خواهش اڃا تائين ناهي، غير مطابقت واري ان پٽ-آئوٽ، مان هڪ آسان حل ڳولڻ چاهيان ٿو. پهرين شيء جيڪا ذهن ۾ آئي هئي بفر جي سائيز کي وڌائڻ لاء

setvbuf(file, nullptr, _IOFBF, 64* 1024)

پر مون نتيجي ۾ ڪا خاص بهتري نه آئي (هاڻي في لکت تقريباً 37 سيڪڙو وقت جي حساب سان آهي) - جنهن جو مطلب آهي ته اهو اڃا تائين ڊسڪ تي بار بار ڊيٽا لکڻ جو معاملو ناهي. fwrite جي "هوڊ هيٺ" ڏسي رهيا آهيو، توهان ڏسي سگهو ٿا ته هڪ لاڪ / انلاڪ فائل جي جوڙجڪ ڪجهه هن طرح ٿي رهي آهي (سيوڊ ڪوڊ، سڀ تجزيو Visual Studio 2017 تحت ڪيو ويو):


size_t fwrite (const void *buffer, size_t size, size_t count, FILE *stream)
{
   size_t retval = 0;
   _lock_str(stream);   /* lock stream */
   __try
   {
      retval = _fwrite_nolock(buffer, size, count, stream);
   }
   __finally 
   {
       _unlock_str(stream);   /* unlock stream */
   }
   return retval;
}

پروفائلر جي مطابق، _fwrite_nolock وقت جي صرف 6٪ لاء اڪائونٽ، باقي مٿي آهي. منهنجي خاص صورت ۾، موضوع جي حفاظت واضح طور تي ختم ٿي وئي آهي، تنهنڪري مان ان کي قربان ڪندس fwrite ڪال کي تبديل ڪندي _fwrite_nolock - توهان کي دليلن سان هوشيار ٿيڻ جي به ضرورت ناهي. ڪُل: هي سادو هٿرادو نتيجن کي رڪارڊ ڪرڻ جي قيمت کي خاص طور تي گهٽائي ڇڏيو، جيڪو اصل نسخي ۾ خرچ ڪيل وقت جي لڳ ڀڳ اڌ جي برابر آهي. رستي جي ذريعي، POSIX دنيا ۾ ھڪڙو ساڳيو فنڪشن آھي - fwrite_unlocked. عام طور تي ڳالهائڻ، ساڳيو ئي فريڊ تي لاڳو ٿئي ٿو. اهڙيءَ طرح، #defines جو هڪ جوڙو استعمال ڪندي، توهان حاصل ڪري سگهو ٿا مڪمل طور تي پارٽ پليٽ فارم حل بغير غير ضروري لاڪ جي جيڪڏهن اهي ضروري نه هجن (۽ اهو گهڻو ڪري ٿئي ٿو).

fwrite, _fwrite_nolock, setvbuf

اچو ته اصل منصوبي کان پري وڃون ۽ هڪ مخصوص ڪيس جي جانچ تي ڌيان ڏيون: هڪ وڏي فائل (512 ايم بي) کي انتهائي ننڍڙن ٽڪرن ۾ لکڻ - هر هڪ بائيٽ. ٽيسٽ سسٽم: AMD Ryzen 7 1700، 16 GB RAM، 7200 rpm HDD، 64 ايم بي ڪيش. Windows 10 1809 ۾، بائنري 32-بٽ جي طور تي ٺهيل هئي، اصلاحون فعال آهن، لائبريري جامد طور تي ڳنڍيل آهي.

آزمائش لاءِ نمونو:


#include <chrono>
#include <cstdio>
#include <inttypes.h>
#include <memory>

#ifdef _MSC_VER
#define fwrite_unlocked _fwrite_nolock
#endif

using namespace std::chrono;

int main()
{
    std::unique_ptr<FILE, int(*)(FILE*)> file(fopen("test.bin", "wb"), fclose);
    if (!file)
        return 1;

    constexpr size_t TEST_BUFFER_SIZE = 256 * 1024;
    if (setvbuf(file.get(), nullptr, _IOFBF, TEST_BUFFER_SIZE) != 0)
        return 2;

    auto start = steady_clock::now();
    const uint8_t b = 77;
    constexpr size_t TEST_FILE_SIZE = 512 * 1024 * 1024;
    for (size_t i = 0; i < TEST_FILE_SIZE; ++i)
        fwrite_unlocked(&b, 1, sizeof(b), file.get());

    auto end = steady_clock::now();
    auto interval = duration_cast<microseconds>(end - start);
    printf("Time: %lldn", interval.count());

    return 0;
}

متغير هوندا TEST_BUFFER_SIZE، ۽ ڪجھ ڪيسن لاءِ اسين fwrite_unlocked کي fwrite سان تبديل ڪنداسين. اچو ته fwrite ڪيس سان شروع ڪريون بغير واضح طور تي بفر جي سائيز کي ترتيب ڏيڻ (تبصرو ڪريو setvbuf ۽ لاڳاپيل ڪوڊ): وقت 27048906 µs، لکڻ جي رفتار - 18.93 MB/s. هاڻي اچو ته بفر جي سائيز کي 64 KB تي سيٽ ڪريو: وقت - 25037111 μs، رفتار - 20.44 Mb/s. ھاڻي اچو ته _fwrite_nolock جي آپريشن کي جانچون بغير ڪال ڪرڻ جي setvbuf: 7262221 µs، رفتار - 70.5 Mb/s!

اڳيون، اچو ته تجربو ڪريون بفر سائيز (setvbuf):

C/C++ فائل I/O کي تيز ڪريو بغير ڪنهن پسڻ جي

ڊيٽا 5 تجربن جي اوسط ذريعي حاصل ڪئي وئي؛ مان غلطين کي ڳڻڻ ۾ تمام سست هو. جيئن ته منهنجي لاءِ، 93 MB/s جڏهن 1 بائيٽ کي باقاعده HDD تي لکڻ تمام سٺو نتيجو آهي، توهان کي صرف بهتر بفر سائيز کي چونڊڻ جي ضرورت آهي (منهنجي صورت ۾، 256 KB بلڪل صحيح آهي) ۽ fwrite کي _fwrite_nolock/fwrite_unlocked سان تبديل ڪريو ( صورت ۾ جيڪڏھن سلسلي جي حفاظت جي ضرورت نه آهي، يقينا).
ساڳيءَ طرح ساڳي حالتن ۾ فريڊ سان. جيئن ته مون وٽ لينڪس جي هارڊويئر مشين هٿ ۾ نه آهي (سنگل بورڊ ڪمپيوٽرن کي ڳڻپ ناهي)، مون هڪ مجازي مشين تي محدود تجربو ڪرڻ جو فيصلو ڪيو (Hyper-V, OpenSUSE 15, GCC 8.3.1) - جي نموني، اصول ۾، ساڳيو آهي: "ننگ" fwrite 20 Mb/s، fwrite + 256 KB بفر پيدا ڪيو 23 Mb/s، fwrite_unlocked ساڳئي بفر سان - 35 Mb/s (64-bit بائنري، گڏ ٿيل g++ -o2 - s -static-libgcc -static-libstdc++ fwrite_test. cpp -o fwrite_test).

پوء

هن آرٽيڪل لکڻ جو مقصد ڪيترن ئي ڪيسن ۾ هڪ سادي ۽ اثرائتي ٽيڪنڪ کي بيان ڪرڻ هو (مان اڳ ۾ ڪڏهن به _fwrite_nolock/fwrite_unlocked افعال ۾ نه آيو آهيان، اهي تمام مشهور نه آهن - پر بيڪار). مان اهو نه ٿو سمجهان ته مواد نئون آهي، پر مون کي اميد آهي ته مضمون ڪميونٽي لاء مفيد ثابت ٿيندو.

جو ذريعو: www.habr.com

DDoS تحفظ سان سائيٽن لاءِ قابل اعتماد هوسٽنگ خريد ڪريو، VPS VDS سرور 🔥 DDoS تحفظ سان قابل اعتماد ويب سائيٽ هوسٽنگ خريد ڪريو، VPS VDS سرورز | ProHoster