Avoiding implicit try finally section/id

From Free Pascal wiki
Jump to navigationJump to search

English (en) suomi (fi) Bahasa Indonesia (id) русский (ru)

Adakalanya berguna untuk mengetahui bahwa kompilator dapat melapisi beberapa kode dalam blok implisit try ... finally. Intinya ini diperlukan saat anda menggunakan variabel tipe apapun yang harus diinisialisasi / difinalisasi (misalnya prosedur standar Initialize() dan Finalize() melakukan sesuatu yang berarti dengannya), seperti AnsiString atau Variant atau array dinamis. Atau (hanya dalam FPC sebelum tertanggal 2004-12-26) resource string.

Contohnya prosedur seperti

procedure P;
var S: AnsiString;
begin
 ... do something with S ...
end;

sebenarnya dikompilasi seperti

procedure P;
var S: AnsiString;
begin
 Initialize(S);
 try
  ... do something with S ...
 finally Finalize(S) end;
end;

Ini diperlukan, untuk memastikan jumlah referensi dari S yang akan dikurangi dengan benar saat prosedur P kan keluar dengan eksepsi. Tapi dalam beberapa kasus ini dapat mempengaruhi secara signifikan kecepatan atas kode yang diberikan.

Ini adalah link ke diskusi yang diarsipkan pada daftar fpc-devel berkenaan dengan isu ini, dengan subyek "TList slowness in classes" : http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg01367.html

Catatan bahwa ansistring temp vars dapat dibuat secara implisit. Cara yang paling nyata untuk memastikan apa yang terjadi padanya adalah membaca output asm.

Solusi yang Mungkin

  • BARU! gunakan {$implicitexceptions off} Pastikan bahwa anda hanya menggunakan ini pada versi rilis dari program anda. Mendebug dapat menjadi masalah dengan sakalr terutama mencari kebocoran memori dan kerusakan.
  • pisahkan kode yang jarang digunakan yang menyebabkan implisit try finally ke dalam prosedur terpisah. (anda dapat menggunakan prosedure dalam procedure) (diverifikasi)
  • gunakan parameter const daripada parameter nilai. (hindari untuk mengubah refcount tapi temps masih dapat bermasalah).
  • gunakan global vars. (harus berhati-hati dengan masalah reentrency di sini dan temps masih dapat bermasalah).
  • gunakan non tipe refcounted seperti shortstrings.

Program Demo

Dan di bawah ini adalah program demo kecil yang

  • Ketika dijalankan, dengan jelas memperlihatkan bahwa menghindari implisit blok try ... finally dapat menjadikan kode jauh lebih cepat. Ketika saya menjalan program ini pada sistem saya, Saya memperoleh
Time of Foo_Normal: 141
Time of Foo_Faster: 17
  • Memperlihatkan trik bagaimana untuk menghindari implisit blok try ... finally (tanpa mengubah arti atau keamanan kode) dalam beberapa kasus (ketika anda tidak memerlukannya gunakan AnsiString/Variant/something setiap kali procedure dipanggil tapi misalnya hanya jika beberapa parameter memiliki nilai tertentu).
{$mode objfpc}{$H+}

uses
  {BaseUnix, Unix hanya diperlukan untuk mengimplementasi Clock} BaseUnix, Unix,
  SysUtils;

function Clock: Int64;
var Dummy: tms;
begin
 Clock := FpTimes(Dummy);
end;

procedure Foo_Normal(i: Integer);
var S: string;
begin
 if i = -1 then
 begin
  S := 'Some operation with AnsiString';
  raise Exception.Create(S);
 end;
end;

procedure Foo_Faster(i: Integer);

  procedure RaiseError;
  var S: string;
  begin
   S := 'Some operation with AnsiString';
   raise Exception.Create(S);
  end;

begin
 if i = -1 then RaiseError;
end;

{ Catatan bahwa ketika saya memanggil Foo_Normal dan Foo_ResourceString
  i selalu >= 0 maka Eksepsi tidak pernah dimunculkan.
  Maka konstan string SNormal dan SResString tidak benar-benar dipakai. }

const
  TestCount = 10000000;
var
  i: Integer;
  Start: Int64;
begin
 Start := Clock;
 for i := 0 to TestCount do Foo_Normal(i);
 Writeln('Time of Foo_Normal: ', Clock - Start);

 Start := Clock;
 for i := 0 to TestCount do Foo_Faster(i);
 Writeln('Time of Foo_Faster: ', Clock - Start);
end.