Performance 检查文件是否更快';在加载之前存在,或者在异常不存在时捕获异常';不存在?

Performance 检查文件是否更快';在加载之前存在,或者在异常不存在时捕获异常';不存在?,performance,delphi,if-statement,try-except,Performance,Delphi,If Statement,Try Except,有人建议我使用第二个try-except变体,但我也想知道其他人的想法:下面两个过程中哪一个(如果有的话)更省时 procedure LoadImage(img: TImage; filename: string); begin if fileexists(filename) then img.Picture.Loadfromfile(filename) else img.Picture.Loadfromfile('default.jpg') end; 或 问题的一个问

有人建议我使用第二个try-except变体,但我也想知道其他人的想法:下面两个过程中哪一个(如果有的话)更省时

procedure LoadImage(img: TImage; filename: string);
begin
  if fileexists(filename) then
    img.Picture.Loadfromfile(filename)
  else
    img.Picture.Loadfromfile('default.jpg')
end;


问题的一个问题是没有指定所需的语义。有两种可能的解释,哪种解决方案更好取决于这一选择。我假设无法加载回退是一个致命错误

  • 如果第一个文件确实存在,请加载它,否则请加载第二个文件。如果第一个文件存在,但无法加载,则显示错误
  • 如果无法加载第一个文件,请回退到第二个文件
  • 如果您想要1)的语义,那么您的第一个代码就可以了

    如果您想要2)的语义,这两者都不好。第一个代码没有这些语义,因为:

  • 它有一个竞赛条件。如果在检查文件是否存在和加载文件之间删除了图像,则图像将失败
  • 如果文件存在,但无法加载,将引发异常。如果文件不是有效图像或无法打开,则可能发生这种情况
  • 第二种方法对一种常见情况使用异常,这是不好的

    因此,为了实现第二种语义,我将使用:

    procedure LoadImage(img: TImage; filename: string);
    var success:boolean;
    begin
      success := false;
      if FileExists(filename)
        then try
          img.Picture.LoadFromFile(filename);
          success := true;
        except
        end
      if not success
        then img.Picture.LoadFromFile('default.jpg');
    end;
    
    在打开之前检查是否存在会使错误案例更快,但成功案例会更慢。所以哪一个更快取决于你的使用情况

    就我个人而言,我会在第二个变量上使用第三个变量,即使映像只是偶尔丢失,因为我认为正常运行的应用程序不应该抛出异常。我只关心性能问题,如果基准测试显示它是明显的


    <>你也应该考虑一个更有针对性的例外条款。所有的例外都是糟糕的风格。不幸的是,我找不到一个明确的规范,说明哪些异常是由
    TPicture.LoadFromFile
    引发的,所以我现在将保留在总括条款中。

    如果时间效率是您唯一的标准,那么第一个将更快,因为异常处理会消耗CPU

    FileExists()使用一个WinApi调用,因此速度很快,但它只检查文件是否存在。
    若文件存在,但格式不正确或被其他线程阻止,则会出现未处理的异常

    忘记效率。代码的可读性非常重要。过早优化是各种罪恶的根源

    第一个目标是明确的。每个人都可以很容易地弄清楚到底发生了什么

    第二个让我停下来说“什么…?”



    您永远不希望您的代码引起第二种反应。

    它们不是等价的。第一个映像至少有两个问题:1)竞争条件2)如果文件存在,但无法加载,它将引发异常。第一个映像多久存在一次?第一个代码优化了错误情况,第二个代码优化了成功情况。。不要微优化速度快几个数量级的代码。不是非此即彼,你应该检查文件是否存在并捕获错误。我真的不喜欢通过try excepts定义程序流。只是一个建议,如果您计划多次加载
    Default.jpg
    ,那么最好先预加载此图像一次,然后保持加载状态,每次需要时都使用已加载的版本,而不是一遍又一遍地从文件中加载它。现在,您首先从文件名加载,然后将其丢弃以加载default.jpg。缺少
    else
    。我不会使用空的except子句,这是自找麻烦。永远不要离开,except子句为空。永远@NickHodges如果代码仍然包含
    try LoadFromFile(filename),那么代码的作用与它所做的完全相同;除了LoadFromFile('default.jpg');结束。我同意
    除了end
    不好,但是
    除了LoadFromFile('default.jpg');end
    同样糟糕。我建议使用更具体的异常筛选,因此它只捕获与IO相关的异常。但是我在文档中找不到一个声明,说明这个方法可能抛出哪些异常。你有好的消息来源吗?但是将其留空并不比原始问题中的操作更糟糕。您确定
    FileExists()
    的开销小于异常处理的开销吗?即使路径可能是指向慢速服务器的UNC路径?(差别可能很小,哪一个更快并不重要。)只有在实际抛出异常时,异常处理才会很昂贵。尝试。。except代码本身不会减慢执行速度。@至少在旧版本的delphi中,mjn输入
    try…except
    子句会减慢执行速度。与IO的成本相比,可能可以忽略不计,但您不希望在一个紧密的循环中进行
    try-except
    ,即使它从未真正抛出。在Delphi 4和Delphi 2005中,@code,输入try-except块涉及两个堆栈推送和一个mov,并且我认为从那时起它没有改变。你说的是几岁?可能是4岁或6岁。根据我记忆中的try-except(或者可能是try-finally)涉及到对昂贵的windows API函数的调用,这些函数与结构化异常处理有关。清除错误的代码永远不应该比不太清楚的正确代码更可取。不,我不是说第二个是正确的。@hvd:“清除错误的代码永远不应该比不太清楚的正确代码更可取。”——这是不言而喻的。当然,正确清晰的代码是最好的。完全同意。我评论,因为第一个和第二个都不是,我读到你的答案,说第一个是正确的,如果你认为第一个正确的话,这取决于所需的语义学。错误回退和丢失文件回退是不同的,我不知道OP想要哪一个。你还没有回答这个问题。抱怨这个问题与你的想法一样是可以的
    procedure LoadImage(img: TImage; filename: string);
    var success:boolean;
    begin
      success := false;
      if FileExists(filename)
        then try
          img.Picture.LoadFromFile(filename);
          success := true;
        except
        end
      if not success
        then img.Picture.LoadFromFile('default.jpg');
    end;