Avoiding implicit try finally section/fi
Bahasa Indonesia · English · Suomi · Русский
Epäsuoran try finally lohkon välttäminen
Yleistä
Koodin optimoinnissa se auttaa ymmärtämään, että kääntäjä käärii tiettyjä koodirakenteita epäsuorasti try … finally-lohkoon. Tämä on tarpeen aina, kun käytetään sellaisia muuttujia, kuten ansiString, variants tai dynaamisia taulukoita jotka edellyttävät initialization ja finalization (esim. kun standardi aliohjelmat initialize ja finalize tarvitaan oikean muistin allokoinnin ja hankitun muistin vapauttamiseksi).
Tällöin kääntäjä varmistaa, että msg: n viitenumero lasketaan asianmukaisesti, kun menettely doSomething poistuu poikkeuksella. Usein tämä voi kuitenkin aiheuttaa merkittäviä haitallisia vaikutuksia tuotetun koodin nopeuteen.
Tämä oli ongelma, joka oli fpc-devel -sähköpostilistan aiheketjussa http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg01367.html TList slowness classes .
Huomaa, että väliaikaiset ansiString-muuttujat voidaan luoda epäsuorasti. Ainoa tapa olla täysin varma siitä, mitä todellisuudessa tehdään, on lukea assemblerin ulostulo.
Mahdolliset ratkaisut
- Käytetään {$implicitexceptions off}: Varmistetaan, että tämä koskee vain julkaistuja versioita. Virheenjäljitys voi muuttua hankalaksi, kun siirrytään erityisesti muistivuotoihin ja korruptioon.
- Irrotetaan harvoin käytetty koodi, joka aiheuttaa implisiittisen
try…finallyeri aliohjelmiin. (Voidaan käyttää aliohjelmissa aliohjelmia) - Käytetään const parametreja arvoparametrien sijaan. Näin vältetään tarve muuttaa viittausosoitusta, mutta tilapäiset muuttujat voivat edelleen olla ongelma.
- Käytetään globaaleja muuttujia: Sinun on kuitenkin oltava varovainen uusintakysymyksissä, mutta väliaikaiset muuttujat voivat silti olla ongelma.
- Käytetään ei-viitteellisiä tyyppejä, kuten shortstring.
riskejä ja milloin niitä sovelletaan
Warning: Nämä poikkeuskehykset luodaan syystä. Jos niistä jätetään poikkeus niin koodiin jään muistivuoto mahdollisuus
Vuonna 2007 {$implicitExceptions} lisättiin strutils-käännösyksikköön. Jota sysutils on luultavasti seurannut. Tätä varten noudatettiin seuraavaa lähestymistapaa:
- Rutiini, joka kutsuu rutiinia, joka nostaa poikkeuksia, on vaarallinen - esim.
strToInt, mutta eistrToIntDef. - Poikkeuksia aiheuttavat rutiinit on huomioitavia.
- Hyvin suuret rutiinit eivät ole vaivan arvoista, koska riski ja alhaiset edut - esim. päivämäärän muotoilurutiinit.
- Desimaalilukujen käyttö voi nostaa poikkeuksia, jotka muunnetaan sysUtils-ohjelmien avulla. En ole varma, onko tämä todellakin riittävä syy, mutta ohitin Desimaalilukujen käytön käyttämällä näitä rutiineja aluksi tästä syystä.
Jos havaitset näitä muutoksia, ota yhteyttä Marcoviin.
Demo-ohjelma
Alla on pieni demo-ohjelma
Sen suorittaessaan osoittaa selvästi, että epäsuoran try … finally välttäminen mhdollistaa koodin suorittamisen paljon nopeammin. Kun suoritin tämän ohjelman järjestelmässäni, sain tuloksen:
time of fooNormal: 141
time of fooFaster: 17- Tässä näytetään temppu, jolla vältetään epäsuoria
try … finally- lohkoja (muuttamatta koodin merkitystä tai turvallisuutta) joissakin tapauksissa (kun sinun ei tarvitse tosiasiallisesti käyttää tätä AnsiString/
Variant-tyyppiä/ jotakin muuta tyyppiä joka kerta kun aliohjelmaa kutsutaan mutta vain jos jollakin parametrilla on tietty arvo).
program implicitExceptionDemo(input, output, stderr);
// for exceptions
{$mode objfpc}
// data type 'string' refers to 'ansistring'
{$longstrings on}
uses
{$IFDEF UNIX}
// baseUnix, unix needed only to implement clock
BaseUnix, Unix,
{$ENDIF}
sysUtils;
function clock(): int64;
var
{$IFDEF UNIX}
dummy: tms;
{$ELSE}
TS : TTimeStamp;
{$ENDIF}
begin
{$IFDEF UNIX}
clock := fpTimes(dummy);
{$ELSE}
TS:=DateTimeToTimeStamp(Now);
result := TS.Time;
{$ENDIF}
end;
// Note: when fooNormal and fooFaster are called
// i is always >= 0, so no exception is ever actually raised.
// So string constants SNormal and SResString are not really used.
procedure fooNormal(i: integer);
var
s: string;
begin
if i = -1 then
begin
s := 'Some operation with AnsiString';
raise exception.create(s);
end;
end;
procedure fooFaster(i: integer);
procedure raiseError;
var
s: string;
begin
s := 'Some operation with AnsiString';
raise exception.create(s);
end;
begin
if i = -1 then
begin
raiseError;
end;
end;
// M A I N =================================================
const
testCount = 10000000;
var
i: integer;
start: int64;
begin
start := clock();
for i := 0 to testCount do
begin
fooNormal(i);
end;
writeLn('time of fooNormal: ', clock() - start);
start := clock();
for i := 0 to testCount do
begin
fooFaster(i);
end;
writeLn('time of fooFaster: ', clock() - start);
end.Laittamalla raiseError toiseen näkyvyyteen fooFaster aliohjelmassa, keskeysten käsittely ei tule osaksi pääkäyttöistä suoritusosaa.
From the Free Pascal wiki, page "Avoiding implicit try finally section/fi", as it stood on 2022-08-06 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.