Difference between revisions of "Avoiding implicit try finally section/fi"
(Created page with "{{Avoiding implicit try finally section}} = Epäsuoran try finally lohkon välttäminen = ==Yleistä== Koodin optimoinnissa se auttaa ymmärtämään, että Compiler/fi|...") |
|||
Line 6: | Line 6: | ||
Koodin optimoinnissa se auttaa ymmärtämään, että [[Compiler/fi|kääntäjä]] käärii tiettyjä koodirakenteita epäsuorasti | Koodin optimoinnissa se auttaa ymmärtämään, että [[Compiler/fi|kääntäjä]] käärii tiettyjä koodirakenteita epäsuorasti | ||
− | [[Try/fi|<syntaxhighlight lang="pascal" | + | [[Try/fi|<syntaxhighlight lang="pascal" inline>try </syntaxhighlight>]] … |
− | [[Finally/fi|<syntaxhighlight lang="pascal" | + | [[Finally/fi|<syntaxhighlight lang="pascal" inline>finally</syntaxhighlight>]]-[[Block/fi|lohkoon]]. |
− | Tämä on tarpeen aina, kun käytetään sellaisia [[Variable/fi|muuttujia]], kuten [[Ansistring|<syntaxhighlight lang="pascal" | + | Tämä on tarpeen aina, kun käytetään sellaisia [[Variable/fi|muuttujia]], kuten [[Ansistring|<syntaxhighlight lang="pascal" inline>ansiString</syntaxhighlight>]], |
− | [[Variant|<syntaxhighlight lang="pascal" | + | [[Variant|<syntaxhighlight lang="pascal" inline>variant</syntaxhighlight>s]] tai [[Dynamic array/fi|dynaamisia taulukoita]] jotka edellyttävät [[Initialization|initialization]] ja [[Finalization|finalization]] (esim. kun standardi [[Procedure/fi|aliohjelmat]] <syntaxhighlight lang="pascal" inline>initialize</syntaxhighlight> ja <syntaxhighlight lang="pascal" inline>finalize</syntaxhighlight> 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ä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 <tt>fpc-devel</tt> -sähköpostilistan aiheketjussa http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg01367.html <syntaxhighlight lang="pascal" | + | Tämä oli ongelma, joka oli <tt>fpc-devel</tt> -sähköpostilistan aiheketjussa http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg01367.html <syntaxhighlight lang="pascal" inline>TList</syntaxhighlight> slowness classes . |
− | Huomaa, että väliaikaiset <syntaxhighlight lang="pascal" | + | Huomaa, että väliaikaiset <syntaxhighlight lang="pascal" inline>ansiString</syntaxhighlight>-muuttujat voidaan luoda epäsuorasti. Ainoa tapa olla täysin varma siitä, mitä todellisuudessa tehdään, on lukea [[Assembler/fi|assemblerin]] ulostulo. |
== Mahdolliset ratkaisut == | == Mahdolliset ratkaisut == | ||
− | * Käytetään [[sImplicitExeptions|<syntaxhighlight lang="pascal" | + | * Käytetään [[sImplicitExeptions|<syntaxhighlight lang="pascal" inline>{$implicitexceptions off}</syntaxhighlight>]]: 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 <syntaxhighlight lang="pascal" | + | * Irrotetaan harvoin käytetty koodi, joka aiheuttaa implisiittisen <syntaxhighlight lang="pascal" inline>try…finally</syntaxhighlight> eri aliohjelmiin. (Voidaan käyttää aliohjelmissa aliohjelmia) |
− | * Käytetään [[Const#const parameter|<syntaxhighlight lang="pascal" | + | * Käytetään [[Const#const parameter|<syntaxhighlight lang="pascal" inline>const</syntaxhighlight> parametreja]] arvoparametrien sijaan. Näin vältetään tarve muuttaa viittausosoitusta, mutta tilapäiset muuttujat voivat edelleen olla ongelma. |
* Käytetään [[Global variables|globaaleja muuttujia]]: Sinun on kuitenkin oltava varovainen uusintakysymyksissä, mutta väliaikaiset muuttujat voivat silti olla ongelma. | * Käytetään [[Global variables|globaaleja muuttujia]]: Sinun on kuitenkin oltava varovainen uusintakysymyksissä, mutta väliaikaiset muuttujat voivat silti olla ongelma. | ||
− | * Käytetään ei-viitteellisiä tyyppejä, kuten [[Shortstring|<syntaxhighlight lang="pascal" | + | * Käytetään ei-viitteellisiä tyyppejä, kuten [[Shortstring|<syntaxhighlight lang="pascal" inline>shortstring</syntaxhighlight>]]. |
== riskejä ja milloin niitä sovelletaan == | == riskejä ja milloin niitä sovelletaan == | ||
Line 30: | Line 30: | ||
− | Vuonna 2007 [[sImplicitExceptions|<syntaxhighlight lang="pascal" | + | Vuonna 2007 [[sImplicitExceptions|<syntaxhighlight lang="pascal" inline>{$implicitExceptions}</syntaxhighlight>]] lisättiin |
− | {{Doc|package=RTL|unit=strutils|text=<syntaxhighlight lang="pascal" | + | {{Doc|package=RTL|unit=strutils|text=<syntaxhighlight lang="pascal" inline>strutils</syntaxhighlight>}}-[[Unit/fi|käännösyksikköön]]. |
− | Jota {{Doc|package=RTL|unit=sysutils|tetx=<syntaxhighlight lang="pascal" | + | Jota {{Doc|package=RTL|unit=sysutils|tetx=<syntaxhighlight lang="pascal" inline>sysUtils</syntaxhighlight>}} on luultavasti seurannut. Tätä varten noudatettiin seuraavaa lähestymistapaa: |
− | * [[Routine/fi|Rutiini]], joka kutsuu rutiinia, joka [[Raise/fi|nostaa]] poikkeuksia, on vaarallinen - esim. {{Doc|package=RTL|unit=sysutils|identifier=strtoint|text=<syntaxhighlight lang="pascal" | + | * [[Routine/fi|Rutiini]], joka kutsuu rutiinia, joka [[Raise/fi|nostaa]] poikkeuksia, on vaarallinen - esim. {{Doc|package=RTL|unit=sysutils|identifier=strtoint|text=<syntaxhighlight lang="pascal" inline>strToInt</syntaxhighlight>}}, mutta ei {{Doc|package=RTL|unit=sysutils|identifier=strtointdef|text=<syntaxhighlight lang="pascal" inline>strToIntDef</syntaxhighlight>}}. |
* Poikkeuksia aiheuttavat rutiinit on huomioitavia. | * Poikkeuksia aiheuttavat rutiinit on huomioitavia. | ||
* Hyvin suuret rutiinit eivät ole vaivan arvoista, koska riski ja alhaiset edut - esim. {{Doc|package=RTL|unit=sysutils|identifier=datetimeroutines|text=päivämäärän muotoilurutiinit}}. | * Hyvin suuret rutiinit eivät ole vaivan arvoista, koska riski ja alhaiset edut - esim. {{Doc|package=RTL|unit=sysutils|identifier=datetimeroutines|text=päivämäärän muotoilurutiinit}}. | ||
− | * Desimaalilukujen käyttö voi nostaa poikkeuksia, jotka muunnetaan [[sysutils|<syntaxhighlight lang="pascal" | + | * Desimaalilukujen käyttö voi nostaa poikkeuksia, jotka muunnetaan [[sysutils|<syntaxhighlight lang="pascal" inline>sysUtils</syntaxhighlight>]]-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ä [[User:Marcov|Marcoviin]]. | Jos havaitset näitä muutoksia, ota yhteyttä [[User:Marcov|Marcoviin]]. | ||
Line 50: | Line 50: | ||
time of fooFaster: 17 | time of fooFaster: 17 | ||
− | * Tässä näytetään temppu, jolla vältetään epäsuoria <syntaxhighlight lang="pascal" | + | * Tässä näytetään temppu, jolla vältetään epäsuoria <syntaxhighlight lang="pascal" inline>try … finally</syntaxhighlight> - lohkoja (muuttamatta koodin merkitystä tai turvallisuutta) joissakin tapauksissa (kun sinun ei tarvitse tosiasiallisesti käyttää tätä [[Ansistring|<syntaxhighlight lang="pascal" inline>AnsiString</syntaxhighlight>]]/ |
− | [[Variant|<syntaxhighlight lang="pascal" | + | [[Variant|<syntaxhighlight lang="pascal" inline>Variant</syntaxhighlight>-tyyppiä]]/ jotakin muuta tyyppiä joka kerta kun aliohjelmaa kutsutaan mutta vain jos jollakin parametrilla on tietty arvo). |
Line 142: | Line 142: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Laittamalla <syntaxhighlight lang="pascal" | + | Laittamalla <syntaxhighlight lang="pascal" inline>raiseError</syntaxhighlight> toiseen [[Scope|näkyvyyteen]] <syntaxhighlight lang="pascal" inline>fooFaster</syntaxhighlight> aliohjelmassa, keskeysten käsittely ei tule osaksi pääkäyttöistä suoritusosaa. |
Latest revision as of 17:16, 6 August 2022
│
English (en) │
suomi (fi) │
Bahasa Indonesia (id) │
русский (ru) │
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
,
variant
s 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…finally
eri 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).
1program implicitExceptionDemo(input, output, stderr);
2
3// for exceptions
4{$mode objfpc}
5// data type 'string' refers to 'ansistring'
6{$longstrings on}
7
8uses
9 {$IFDEF UNIX}
10 // baseUnix, unix needed only to implement clock
11 BaseUnix, Unix,
12 {$ENDIF}
13 sysUtils;
14
15function clock(): int64;
16
17var
18 {$IFDEF UNIX}
19 dummy: tms;
20 {$ELSE}
21 TS : TTimeStamp;
22 {$ENDIF}
23begin
24 {$IFDEF UNIX}
25 clock := fpTimes(dummy);
26 {$ELSE}
27 TS:=DateTimeToTimeStamp(Now);
28 result := TS.Time;
29 {$ENDIF}
30end;
31
32
33
34// Note: when fooNormal and fooFaster are called
35// i is always >= 0, so no exception is ever actually raised.
36// So string constants SNormal and SResString are not really used.
37
38procedure fooNormal(i: integer);
39var
40 s: string;
41begin
42 if i = -1 then
43 begin
44 s := 'Some operation with AnsiString';
45 raise exception.create(s);
46 end;
47end;
48
49procedure fooFaster(i: integer);
50 procedure raiseError;
51 var
52 s: string;
53 begin
54 s := 'Some operation with AnsiString';
55 raise exception.create(s);
56 end;
57begin
58 if i = -1 then
59 begin
60 raiseError;
61 end;
62end;
63
64
65// M A I N =================================================
66const
67 testCount = 10000000;
68var
69 i: integer;
70 start: int64;
71begin
72 start := clock();
73 for i := 0 to testCount do
74 begin
75 fooNormal(i);
76 end;
77 writeLn('time of fooNormal: ', clock() - start);
78
79 start := clock();
80 for i := 0 to testCount do
81 begin
82 fooFaster(i);
83 end;
84 writeLn('time of fooFaster: ', clock() - start);
85end.
Laittamalla raiseError
toiseen näkyvyyteen fooFaster
aliohjelmassa, keskeysten käsittely ei tule osaksi pääkäyttöistä suoritusosaa.