Нөлдік көшірмемен деректерді тиімді тасымалдау

Новости мира

Көптеген веб-қосымшалар дискіден деректерді оқуды және оны жауап беретін ұяшыққа жазуды білдіретін статикалық мазмұнның айтарлықтай көлемін шығарады. Бұл әрекет процессорды салыстырмалы түрде аз пайдалануды қажет етуі мүмкін, бірақ ол өте тиімді емес: ядро ​​дискіден деректерді оқиды, оны ядро-пайдаланушы шекарасы арқылы қолданбаға жібереді, содан кейін қолданба ядро-пайдаланушы шекарасы арқылы бірдей деректерді қайтарады. розеткаға жазыңыз. Іс жүзінде қолданба деректерді дискіден розеткаға тасымалдайтын тиімсіз аралық сілтеме ретінде әрекет етеді.

Деректер пайдаланушы ядросының шекарасын кесіп өткен сайын оны көшіру керек; бұл процессор мен жад ресурстарын тұтынады. Бақытымызға орай, бұл көшіруді тиісті атаулы технологиямен, нөлдік көшірмені болдырмауға болады. Нөлдік көшірмені пайдаланатын қолданбалар ядродан қолданбаға әсер етпестен деректерді тікелей дискіден ұяшыққа көшіруді сұрайды. Нөлдік көшірме қолданба өнімділігін айтарлықтай жақсартады және пайдаланушы мен ядро ​​режимдері арасындағы мәтінмәндік қосқыштардың санын азайтады.

Java класс кітапханалары java.nio.channels.FileChannel transferTo() әдісі арқылы Linux және UNIX жүйелерінде нөлдік көшірмені қолдайды. TransferTo() әдісі деректерді қолданба арқылы өткізбей-ақ, олар шақырылатын арнадан басқа жазылатын арнаға тікелей жіберуге мүмкіндік береді. Бұл мақала алдымен дәстүрлі көшірме семантикасын пайдаланып файлдарды тасымалдауға арналған жүйенің үстеме шығынын көрнекі түрде сипаттайды, содан кейін transferTo() арқылы нөлдік көшірме технологиясы арқылы өнімділіктің қалай жақсартылатынын көрсетеді.

Мәліметтерді тасымалдау: дәстүрлі әдіс

Файлдан оқу және деректерді желі арқылы басқа бағдарламаға тасымалдау сценарийін қарастырыңыз. (Бұл сценарий көптеген серверлік қолданбалардың әрекетін сипаттайды, соның ішінде статикалық мазмұнға қызмет көрсететін веб-бағдарламалар, FTP серверлері, пошта серверлері және т.б.) Операцияның мәні 1-тізімде көрсетілген екі қоңырау (толық сілтеме үшін) болып табылады. код мысалы, Жүктеп алу бөлімін қараңыз):

Листинг 1. Файлдан ұяшыққа байттарды көшіру
File.read(fileDesc, buf, len);
Socket.send(сокет, буф, len);

Листинг 1 принципі қарапайым болғанымен, ішкі көшіру операциясы пайдаланушы режимі мен ядро ​​режимі арасында төрт контекстік ауысуды қажет етеді және операция барысында деректер төрт рет көшіріледі. 1-суретте деректердің файлдан ұяшыққа ішкі қалай ауысатыны көрсетілген:

Сурет 1. Деректерді көшірудің дәстүрлі тәсілі

2-суретте контекстік қосқыш көрсетілген:

Сурет 2. Дәстүрлі контекстік қосқыш

Операция қадамдары:
Read() шақыру пайдаланушы режимінен ядро ​​режиміне контекстік ауысуды (2-суретті қараңыз) орындайды. Файлдан деректерді оқу үшін ішкі sys_read() (немесе баламасы) іске қосылады. Бірінші көшірме (1-суретті қараңыз) файлдың мазмұнын дискіден оқитын және оны ядроның мекенжай кеңістігінің буферінде сақтайтын Direct Memory Access (DMA) механизмі арқылы орындалады.

Сұралған деректер көлемі оқу буферінен пайдаланушы буферіне көшіріледі және read() шақыруы қайтарылады. Қоңыраудан келген жауап ядро ​​режимінен пайдаланушы режиміне қайта басқа контекстік қосқышты жасайды. Деректер енді пайдаланушы кеңістігінің мекенжай буферінде.

send() сокет функциясын шақырған кезде контекст пайдаланушы режимінен ядро ​​режиміне ауыстырылады. Үшінші көшірме деректерді ядро ​​мекенжай кеңістігінің буферіне қайта толтыру үшін жасалады. Бұл жолы деректер тағайындалған ұяшықпен байланысты басқа буферге орналастырылады.

Send() төртінші контекстік қосқышты іске қоса отырып, жүйелік шақыруды қайтарады. Төртінші көшірме дербес және асинхронды түрде орын алады, өйткені DMA механизмі деректерді ядро ​​буферінен протокол механизміне тасымалдайды.

Аралық ядро ​​буферін пайдалану (деректерді пайдаланушы буферіне тікелей жіберудің орнына) тиімсіз болып көрінеді. Бірақ өнімділікті жақсарту үшін процестерге аралық ядро ​​буферлері енгізілді. Аралық оқу жағындағы буферді пайдалану ядро ​​буферіне бағдарлама ядро ​​буферінде қамтылғандай көп деректерді сұрамағанда, ядро ​​буферіне «алдын ала оқылатын кэш» ретінде әрекет етуге мүмкіндік береді. Бұл талап етілетін деректер көлемі ядро ​​буферінің өлшемінен аз болғанда өнімділікті айтарлықтай жақсартады. Жазу жағындағы аралық буфер жазуды асинхронды түрде аяқтауға мүмкіндік береді.

Өкінішке орай, егер сұралған деректердің өлшемі ядро ​​буферінің өлшемінен әлдеқайда үлкен болса, бұл әдістің өзі өнімділік кедергісіне айналуы мүмкін. Деректер қолданбаға түспес бұрын диск, ядро ​​буфері және пайдаланушы буфері арасында қайта-қайта көшіріледі.

Нөлдік көшіру әдісі қажетсіз деректерді көшіру қажеттілігін жою арқылы өнімділікті жақсартады.