Difference between revisions of "Avoiding implicit try finally section/fi"

From Lazarus wiki
Jump to navigationJump to search
(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" enclose="none">try </syntaxhighlight>]] …  
+
[[Try/fi|<syntaxhighlight lang="pascal" inline>try </syntaxhighlight>]] …  
[[Finally/fi|<syntaxhighlight lang="pascal" enclose="none">finally</syntaxhighlight>]]-[[Block/fi|lohkoon]].
+
[[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" enclose="none">ansiString</syntaxhighlight>]],  
+
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" enclose="none">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" enclose="none">initialize</syntaxhighlight> ja <syntaxhighlight lang="pascal" enclose="none">finalize</syntaxhighlight> tarvitaan oikean muistin allokoinnin ja hankitun muistin vapauttamiseksi).
+
[[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" enclose="none">TList</syntaxhighlight> slowness classes .
+
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" enclose="none">ansiString</syntaxhighlight>-muuttujat voidaan luoda epäsuorasti. Ainoa tapa olla täysin varma siitä, mitä todellisuudessa tehdään, on lukea [[Assembler/fi|assemblerin]] ulostulo.
+
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" enclose="none">{$implicitexceptions off}</syntaxhighlight>]]: Varmistetaan, että tämä koskee vain julkaistuja versioita. Virheenjäljitys voi muuttua hankalaksi, kun siirrytään erityisesti muistivuotoihin ja korruptioon.
+
* 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" enclose="none">try…finally</syntaxhighlight> eri aliohjelmiin. (Voidaan käyttää aliohjelmissa aliohjelmia)
+
* 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" enclose="none">const</syntaxhighlight> parametreja]] arvoparametrien sijaan. Näin vältetään tarve muuttaa viittausosoitusta, mutta tilapäiset muuttujat voivat edelleen olla ongelma.
+
* 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" enclose="none">shortstring</syntaxhighlight>]].
+
* 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" enclose="none">{$implicitExceptions}</syntaxhighlight>]] lisättiin  
+
Vuonna 2007 [[sImplicitExceptions|<syntaxhighlight lang="pascal" inline>{$implicitExceptions}</syntaxhighlight>]] lisättiin  
{{Doc|package=RTL|unit=strutils|text=<syntaxhighlight lang="pascal" enclose="none">strutils</syntaxhighlight>}}-[[Unit/fi|käännösyksikköön]].
+
{{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" enclose="none">sysUtils</syntaxhighlight>}} on luultavasti seurannut. Tätä varten noudatettiin seuraavaa lähestymistapaa:
+
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" enclose="none">strToInt</syntaxhighlight>}}, mutta ei {{Doc|package=RTL|unit=sysutils|identifier=strtointdef|text=<syntaxhighlight lang="pascal" enclose="none">strToIntDef</syntaxhighlight>}}.
+
* [[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" enclose="none">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ä.
+
* 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" enclose="none">try … finally</syntaxhighlight> - lohkoja (muuttamatta koodin merkitystä tai turvallisuutta) joissakin tapauksissa (kun sinun ei tarvitse tosiasiallisesti käyttää tätä [[Ansistring|<syntaxhighlight lang="pascal" enclose="none">AnsiString</syntaxhighlight>]]/
+
* 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" enclose="none">Variant</syntaxhighlight>-tyyppiä]]/ jotakin muuta tyyppiä joka kerta kun aliohjelmaa kutsutaan mutta vain jos jollakin parametrilla on tietty arvo).
+
[[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" enclose="none">raiseError</syntaxhighlight> toiseen [[Scope|näkyvyyteen]] <syntaxhighlight lang="pascal" enclose="none">fooFaster</syntaxhighlight> aliohjelmassa, keskeysten käsittely ei tule osaksi pääkäyttöistä suoritusosaa.
+
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 tryfinally-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 tryfinally 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-icon.png

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 ei strToIntDef.
  • 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.