Директен достъп до обект = 94 117 пъти по-бързо от четене от файл?

Написах малък клас, който основно извлича данни от CSV файл и ги зарежда в POJO обект. Тъй като имам нужда от чест достъп до тези данни, написах единичен клас, който проверява дали данните вече са в обекта и ако да, просто връща данните директно от обекта (без да е необходимо да ги получава отново от файла). В противен случай той извлича данни от файл и съхранява данни в обект за бъдещи заявки.

При тестване забелязах, че са необходими приблизително 175 милисекунди за достъп до данните 10 000 пъти (включително първия път, който зарежда данните от файл).

Това, което ме порази, беше, че когато зациклих 20 000 пъти, това отне само 177 милисекунди (само две милисекунди повече от 10 000 пъти), а 50 000 пъти отне само около 197 милисекунди.

Какво е обяснението, че е много по-бързо да се направи 50K срещу 10K? Защо времето не се увеличава пропорционално?

Също така защо достъпът до данни директно от обект е много по-бърз от достъпа до него от диск (когато имам достъп до него чрез файл, това отнема около 160 милисекунди за един път)

Благодаря

Актуализация:

Може би още по-объркващо е, че когато се опитвам да осъществя достъп до обекта с помощта на два различни ключа (което изисква две четения от файл), това отнема приблизително същото време (с вариация от 1 милисекунда), отколкото достъпът до него веднъж. Всички обяснения, че достъпът до обекти е 200K пъти по-бърз от достъпа до файлове, обясняват само първото ми наблюдение, но сега всъщност чета данни от два различни файла, но не виждам пропорционално увеличение на времето, което отнема.

С други думи, правейки това:

    for (int counter = 0; counter < 1; counter++) {

        POJOObj.getInstance().getKey("Key1", "Val1");

    }

отнема същото време като това:

for (int counter = 0; counter < 1; counter++) {

        POJOObj.getInstance().getKey("Key1", "Val1");
        POJOObj.getInstance().getKey("Key1", "Val2"); // this requires new read from file

    }

Защо времето не се увеличава пропорционално?


person S.O.S    schedule 29.08.2018    source източник
comment
Достъпът от файл изисква I/O на диска. Достъпът от обекта е направо от паметта. Вижте: stackoverflow.com/questions/1371400/ Трябва също да прочетете основите на това как работи кеширането, което обяснява защо не се увеличава пропорционално, както казвате.   -  person noahnu    schedule 29.08.2018
comment
Защо времето не се увеличава пропорционално? Вероятно защото логиката ви за тестване на ефективността е погрешна. Вижте Как да напиша правилен микробенчмарк в Java?   -  person Andreas    schedule 29.08.2018


Отговори (1)


Четенето на файл от диск е много по-бавно в сравнение с четенето на данни от паметта. Има доста добър ресурс, наречен „Числа на забавяне, които всеки програмист трябва да знае“, който обяснява част от това . По същество четенето на 1 MB от диск е около 200 000 пъти по-бавно от четенето на същото от основната памет.

Що се отнася до причината, поради която виждате по-бързи времена за реакция от вашия метод - Hotspot (вътрешният компилатор на JVM) вероятно се е включил. Когато изпълнявате често метод в Java, JVM ще открие това след определен праг (искам да кажа, че е около 10k извиквания , но не ми вярвайте за това) и оптимизирайте метода. Той прави това, като преобразува интерпретирания байткод, който сте изпълнявали, във вградено асемблиране. Това е много по-бързо и се случва зад кулисите. Писането на микробенчмаркове като вашите е изключително трудно и има много начини това да се обърка. Вижте този ресурс от Oracle за някои от клопки и как да ги избегнете с инструмент, наречен JMH, ако се интересувате от по-нататъшно проучване на тези числа.

person Todd    schedule 29.08.2018
comment
четенето на 1 MB от диск е около 200 000 пъти по-бавно от четенето на същото от основната памет И това е идеално, вероятно за нещо като бързо SSD. Прецакайте своя IO достатъчно зле на бавно SATA устройство, което може да направи само около 40 или 50 търсения на глава/секунда и четенето на MB може да отнеме до 30 или 40 секунди. - person Andrew Henle; 29.08.2018