Кіріспе
Функция шақыруын сол функцияның бастапқы кодымен алмастыруды оңтайландыру. Есептеуде, желілік кеңейту немесе инлайнинг – функция шақыру орнын шақырылған функцияның мәтінімен алмастыратын қолмен немесе компилятордың оңтайландыруы. Желілік кеңейту макро кеңейтуге ұқсас, бірақ ол компиляция кезінде жүзеге асырылады және бастапқы кодты (мәтінді) өзгертпейді, ал макро кеңейту компиляциядан бұрын болады және компилятор өңдейтін басқа мәтінді құрайды. Инлайнинг маңызды оңтайландыру болып табылады, бірақ өнімділікке күрделі әсер етеді. Қағида бойынша, шамалы инлайнинг жылдамдықты минимал көлем шығынымен жақсартады, бірақ шамадан тыс инлайнинг жылдамдықты төмендетеді, себебі инлайн код тым көп нұсқаулық кэшін пайдаланады және айтарлықтай орынды қажет етеді. 1980 және 1990 жылдардағы инлайнинг туралы шағын академиялық әдебиеттерге шолу Peyton Jones & Marlow 1999 жұмысында келтірілген.
In computing, inline expansion, or inlining, is a manual or compiler optimization that replaces a function call site with the body of the called function. Inline expansion is similar to macro expansion, but occurs during compilation, without changing the source code (the text), while macro expansion occurs prior to compilation, and results in different text that is then processed by the compiler. Inlining is an important optimization, but has complicated effects on performance. As a rule of thumb, some inlining will improve speed at very minor cost of space, but excess inlining will hurt speed, due to inlined code consuming too much of the instruction cache, and also cost significant space. A survey of the modest academic literature on inlining from the 1980s and 1990s is given in Peyton Jones & Marlow 1999.
Шолу
Инлайн кеңейту макро кеңейтуге ұқсас, себебі компилятор функцияның жаңа көшірмесін оның шақырылған әрбір орнына қояды. Инлайн функциялар әдеттегі функциялардан сәл жылдам жұмыс істейді, себебі функцияны шақыруға байланысты қосымша шығындар жойылса да, жад тұтынуы артады. Егер функция 10 рет инлайн болса, кодқа функцияның 10 көшірмесі енгізіледі. Сондықтан инлайнинг жиі шақырылатын кіші функциялар үшін тиімді. C++-та, егер сыныптың мүше функциялары сынып анықтамасының ішінде берілсе, олар әдепкі бойынша инлайн болады (инлайн кілт сөзін пайдалану қажет емес); әйтпесе, кілт сөз қажет. Компилятор бағдарламашының функцияны инлайнға салу әрекетін қабылдамауы мүмкін, әсіресе функция өте үлкен болса. Функция шақырылғанда болатын уақыт шығынын (артық уақытты) жою үшін инлайн кеңейту қолданылады. Ол көбінесе жиі орындалатын функциялар үшін қолданылады. Бұған қоса, өте кішкентай функциялар үшін жадты үнемдеуге және басқа оңтайландыруларға мүмкіндік береді. Инлайн функциялар болмаса, компилятор қай функцияларды инлайнға қосу керектігін шешеді. Бағдарламашы инлайнға қосылатын және қосылмайтын функцияларды бақылауға ие болмайды. Бағдарламашыға осы деңгейдегі бақылау беру, қай функцияларды инлайнға қосу керектігін таңдауда қолданбаға тән білімді пайдалануға мүмкіндік береді. Кәдімгі жағдайда, функция шақырылғанда, басқару тармақ немесе шақыру нұсқаулығы арқылы оның анықтамасына беріледі. Инлайн болғанда, басқару функцияның кодына тікелей түседі, тармақ немесе шақыру нұсқаулығысыз. Компиляторлар әдетте инлайнингпен бірге операторларды іске асырады. Цикл шарттары мен цикл денелеріне ленивый бағалау қажет. Бұл қасиет цикл шарттарын және цикл денелерін есептеу коды инлайн болған кезде орындалады. Орындалу мәселелері – инлайнингтің тағы бір себебі. Функционалдық бағдарламалау тілдерінде инлайн кеңейту әдетте бета-редукция трансформациясымен жүзеге асырылады. Бағдарламашы бастапқы кодқа бір реттік операция ретінде функцияларды көшіру-қою арқылы қолмен инлайнға түсіруі мүмкін. Дегенмен, инлайнингті басқарудың басқа әдістері (төменде қараңыз) артықшылықты, себебі олар бағдарламашы бастапқы функцияның (мүмкін өзгертілген) көшірмесін қадағалауды ұмытқан кезде туындайтын қателерге әкеп соқпайды.
Компиляторды қолдау
Компиляторлар функция шақыруларын инлайнға қосу қажеттігін анықтау үшін әртүрлі механизмдерді пайдаланады; оларға бағдарламашылардан нақты функциялар үшін қолмен берілетін ұсыныстар және командалық жол опциялары арқылы жалпы басқару кіреді. Көптеген тілдердегі көптеген компиляторлар инлайнды автоматты түрде жасайды, бұл инлайнның тиімділігіне байланысты, ал кейбір жағдайларда оны компилятор директивалары арқылы қолмен, әдетте "inline" кілт сөзі немесе компилятор директивасын пайдалана отырып, көрсетуге болады. Әдетте, мұндай ұсыныс инлайнды міндетті етудің орнына, тек қана инлайн қаланын көрсетеді, және осы ұсыныстың күші тіл мен компиляторға қарай өзгереді. Компиляторды жасаушылар әдетте жоғарыда аталған өнімділік мәселелерін ескереді және компиляторларына эвристикалық алгоритмдерді енгізеді, олар көбінесе өнімділікті нашарлатудың орнына, жақсарту үшін қай функцияларды инлайнға қосуды таңдайды.
Шектеулер
Толық желідегі кеңейту рекурсияға байланысты әрқашан мүмкін емес: рекурсивті түрде кеңейтілген шақырулар тоқтамайды. Шешімдердің әртүрлі түрлері бар, мысалы, белгілі бір мөлшерде кеңейту немесе шақыру графигін талдап, белгілі бір түйіндерде циклдарды үзу (яғни, рекурсивті циклдегі кейбір байланысты кеңейтпеу). Дәл осындай мәселе макро кеңеюде де кездеседі, себебі рекурсивті кеңею аяқталмайды және әдетте рекурсивті макроларға тыйым салу арқылы шешіледі (C және C++ тілдеріндегідей).
Макролармен салыстыру
Дәстүрлі түрде, C сияқты тілдерде, сызықтық кеңейту параметрленген макростарды пайдалану арқылы бастапқы код деңгейінде жүзеге асырылды. C99 стандартында қолжетімді нақты сызықты функцияларды пайдалану, осы тәсілге қарағанда бірнеше артықшылықтар ұсынады: C тілінде макро шақырулары типтік тексеруді немесе аргументтердің дұрыс құрылғанын тексермейді, ал функция шақырулары көбінесе осы тексерулерді жүзеге асырады. C тілінде макрос, функция сияқты мағынада қайтару кілт сөзін пайдалана алмайды (ол макросты кеңейтуді сұраған функцияны тоқтатады, макростың өзі емес). Басқаша айтқанда, макрос өзінің ішіндегі соңғы өрнектің нәтижесінен басқа ештеңе қайтара алмайды. C макростары қарапайым мәтіндік алмастыруды қолданғандықтан, бұл аргументтердің қайта бағалануынан және операциялардың ретінен туындаған күтпеген жанама әсерлерге және тиімсіздікке әкелуі мүмкін. Макролардағы компилятор қателерін түсіну қиын, өйткені олар бағдарламашы жазған кодқа емес, кеңейтілген кодқа сілтеме жасайды. Сондықтан, сызықты кодты жөндеу туралы ақпарат, макро кеңейтілген кодты жөндеуге қарағанда көбінесе пайдалы болады. Көптеген конструкцияларды макростарды пайдалану арқылы түсіндіру қиын немесе мүмкін емес, немесе олар үшін едәуір өзгеше синтаксис қолданылуы керек. Сызықты функциялар, қалыпты функциялар сияқты бірдей синтаксисті пайдаланады және қалауынша оңай сызықты және сызықсыз етуге болады. Көптеген компиляторлар кейбір рекурсивті функцияларды да сызықты кеңейтуге мүмкіндік береді; ал рекурсивті макростар көбінесе рұхсат етілмейді. C++ тілінің жасаушысы Бьярне Строуструп, макростарды мүмкіндігінше болдырмау қажет екенін баса айтады және сызықты функцияларды кеңінен пайдалануды қолдайды.
In C, macro invocations do not perform type checking, or even check that arguments are well formed, whereas function calls usually do. In C, a macro cannot use the return keyword with the same meaning as a function would do (it would make the function that asked the expansion terminate, rather than the macro). In other words, a macro cannot return anything which is not the result of the last expression invoked inside it. Since C macros use mere textual substitution, this may result in unintended side effects and inefficiency due to re evaluation of arguments and order of operations. Compiler errors within macros are often difficult to understand, because they refer to the expanded code, rather than the code the programmer typed. Thus, debugging information for inlined code is usually more helpful than that of macro expanded code. Many constructs are awkward or impossible to express using macros, or use a significantly different syntax. Inline functions use the same syntax as ordinary functions, and can be inlined and un inlined at will with ease. Many compilers can also inline expand some recursive functions; recursive macros are typically illegal. Bjarne Stroustrup, the designer of C++, likes to emphasize that macros should be avoided wherever possible, and advocates extensive use of inline functions.
Таңдау әдістері
Көптеген компиляторлар функцияларды пайдалы болған жағдайларда белсенді түрде ішке енгізеді. Бұл орындалатын файлдардың көлемін арттырса да, жад сыйымдылығы процессор жылдамдығынан тез өскендіктен, белсенді енгізуге деген қажеттілік артып келеді. Ішке енгізу – функционалдық және объектіге бағытталған бағдарламалау тілдеріндегі маңызды оптимизация, олар дәстүрлі оптимизацияларды тиімді ету үшін әдетте кішкентай функцияларына қажетті контексті қамтамасыз етуге сенеді.
C және C++
C және C++ тілдерінде inline кілт сөзі бар, ол компиляторға нұсқау ретінде қызмет етеді – inlining қажет екенін, бірақ міндетті емес екенін көрсетеді, сонымен қатар функцияның көріну қасиетін және байланыс әрекетін өзгертеді. Көріну қасиетін өзгерту стандартты C құралдар жинағы арқылы функцияны inlining-ке мүмкіндік беру үшін қажет, онда жеке файлдардың (немесе аударма бірліктерінің) компиляциясынан кейін байланыс жасалады: байланыс құралына функцияларды inlining-ке мүмкіндік беру үшін, олар header-де (көріну үшін) көрсетілуі керек және inline деп белгіленуі керек (көптеген анықтамалардан туындайтын екіұштылықты болдырмау үшін).