尝试/抓住或验证速度? [英] Try/catch or validation for speed?

查看:112
本文介绍了尝试/抓住或验证速度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Python,每当我必须验证函数输入时,我认为输入有效,然后发现错误。



在我的情况下,我有一个通用的 Vector()类,我用于一些不同的东西,其中之一是添加。它既作为一个 Color()类又作为一个 Vector(),所以当我将标量添加到 Color(),它应该将该常量添加到每个单独的组件。 Vector() Vector()添加需要组件添加。



这个代码正在用于一个raytracer,所以任何速度提升都是很棒的。



这是一个简化版本的我的 Vector() class:

  class Vector:
def __init __(self,x,y,z )
self.x = x
self.y = y
self.z = z

def __add __(self,other):
try :
return Vector(self.x + other.x,self.y + other.y,self.z + other.z)
除了AttributeError:
return Vector(self.x +其他,self.y +其他,self.z +其他)

我正在使用 try ... except 方法。有没有人知道一个更快的方法?






编辑:感谢答案,我试过并测试了以下解决方案,它在添加 Vector()对象之前专门检查类名称:

  class Vector:
def __init __(self,x,y,z):
self.x = x
self.y = y
self $ z
def __add __(self,other):
if type(self)== type(other):
return Vector(self.x + other.x ,self.y + other.y,self.z + other.z)
else:
return Vector(self.x + other,self.y + other,self.z + other)






我用这两个代码块进行了速度测试, timeit ,结果为相当重要:

  1.0528049469 usec / pass for Try ...除了
0.732456922531 usec / pass for If ...其他
比率(第一/第二):1.43736090753

我还没有测试过 Vector )类与输入验证(即将检查移出课堂并进入实际的代码),但是我想象,它比 if ... else 方法更快。






延迟更新:回顾这段代码,这不是一个最佳解决方案



OOP使这更快:

  class Vector:
def __init __(self,x,y,z):
self.x = x
self.y = y
self.z = z

def __add __(self,other):
return Vector(self.x + other.x,self.y + other.y,self.z + other.z)

class颜色(
def __add __(self,other):
if type(self)== type(other):
return Color(self.x + other.x,self.y + other.y,self.z + other.z)
else:
return颜色(self.x + other,self.y + other,self.z + other)


解决方案

我高调了Matt Joiner的答案,但想包括一些额外的观察要明确指出,除了其他一些因素之外,在预先检查条件(称为LBYL或Look Before You Leap之间)之间选择时,还有 4 次,只是处理异常(被称为EAFP或容易询问宽恕而不是允许)。



这些时间是:




  • 使用LBYL
  • 成功获得的时间
  • 检查失败时的时间与LBYL
  • b $ b
  • 使用EAFP
  • 抛出异常时的时间
  • 使用EAFP 抛出异常其他因素有:




    • 典型的检查成功/失败的比例或抛出的异常/未抛出的案例

    • 是否存在阻止使用LBYL的竞争条件



    最后一点是需要首先解决的问题:如果有竞争条件的潜力,那么你别无选择,你必须使用异常处理。一个典型的例子是:

      if< dir不存在> ;: 
    < create dir> #如果另一个进程创建目标目录,可能仍然失败

    由于LBYL不排除异常这样的情况下,它没有真正的好处,没有任何判断要求:EAFP是正确处理竞争条件的唯一方法。



    但是如果没有比赛条件,这两种方法都是可行的。他们提供不同的权衡:




    • 如果没有提出异常,则EAFP接近免费

    • <但是,如果发生异常,则相对较昂贵,因为解包过程涉及很多处理,创建异常并将其与异常处理条款进行比较。
    • LBYL相比之下,产生了高昂的固定成本:无论成功或失败,始终执行附加支票



    以下决策标准:




    • 这段代码是否对应用程序的速度至关重要?那么不要担心两者之中哪一个更快,担心两者之一更容易阅读。

    • 预支票比提高成本贵并捕捉异常?如果是,那么EAFP总是更快,应该使用。

    • 如果答案是否,事情会变得更有趣。在这种情况下,哪个更快将取决于成功或错误情况是否更常见,以及预检和异常处理的相对速度。



    作为一个粗略的经验法则:




    • 如果有潜在的竞争条件,使用EAFP

    • 如果速度不重要,只要使用您认为更容易阅读的任何一个

    • 如果预先检查是昂贵的,使用EAFP

    • 如果您希望操作在大部分时间内成功*,请使用EAFP

    • 如果您期望操作失败超过一半时间,请使用LBYL

    • 如有疑问,请测量



    *在这种情况下,人们会因为大部分时间而被认为是不同的。对我来说,如果我希望这个操作能够在一半以上的时间内取得成功,那么我当然应该使用EAFP,直到我有理由怀疑这段代码是一个实际的性能瓶颈。


    I'm working with Python and whenever I've had to validate function input, I assumed that the input worked, and then caught errors.

    In my case, I had a universal Vector() class which I used for a few different things, one of which is addition. It functioned both as a Color() class and as a Vector(), so when I add a scalar to the Color(), it should add that constant to each individual component. Vector() and Vector() addition required component-wise addition.

    This code is being used for a raytracer so any speed boosts are great.

    Here's a simplified version of my Vector() class:

    class Vector:
      def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    
      def __add__(self, other):
        try:
          return Vector(self.x + other.x, self.y + other.y, self.z + other.z)
        except AttributeError:
          return Vector(self.x + other, self.y + other, self.z + other)
    

    I'm currently using the try...except method. Does anybody know of a faster method?


    EDIT: Thanks to the answers, I tried and tested the following solution, which checks specifically for a class name before adding the Vector() objects:

    class Vector:
      def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    
      def __add__(self, other):
        if type(self) == type(other):
          return Vector(self.x + other.x, self.y + other.y, self.z + other.z)
        else:
          return Vector(self.x + other, self.y + other, self.z + other)
    


    I ran a speed test with these two blocks of code using timeit, and the results were pretty significant:

     1.0528049469 usec/pass for Try...Except
     0.732456922531 usec/pass for If...Else
     Ratio (first / second): 1.43736090753
    

    I haven't tested the Vector() class with no input validation whatsoever (i.e. moving the checking out of the class and into the actual code), but I'd imagine that it's even faster than the if...else method.


    Late update: Looking back at this code, this is not an optimal solution.

    OOP makes this even faster:

    class Vector:
      def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    
      def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)
    
    class Color(Vector):
      def __add__(self, other):
        if type(self) == type(other):
          return Color(self.x + other.x, self.y + other.y, self.z + other.z)
        else:
          return Color(self.x + other, self.y + other, self.z + other)
    

    解决方案

    I upvoted Matt Joiner's answer, but wanted to include some additional observations to make it clear that, along with a couple of other factors, there are 4 times that matter when choosing between pre-checking conditions (known as LBYL or "Look Before You Leap") and just handling exceptions (known as EAFP or "Easier to Ask Forgiveness than Permission").

    Those timings are:

    • Timing when the check succeeds with LBYL
    • Timing when the check fails with LBYL
    • Timing when an exception is not thrown with EAFP
    • Timing when an exception is thrown with EAFP

    The additional factors are:

    • The typical ratio of check success/failure or exception thrown/not thrown cases
    • Whether or not there is a race condition that prevents the use of LBYL

    That last point is the one that needs to be addressed first: if there is a potential for a race condition, then you have no choice, you must use exception handling. A classic example is:

    if <dir does not exist>:
        <create dir> # May still fail if another process creates the target dir
    

    Since LBYL doesn't rule out the exception is such cases, it offers no real benefit and there's no judgement call to be made: EAFP is the only approach that will handle the race condition correctly.

    But if there's no race condition, either approach is potentially viable. They offer different trade-offs:

    • if no exception is raised, then EAFP is close to free
    • however, it is comparatively expensive if an exception occurs, as there is quite a lot of processing involved in unwinding the stack, creating the exception and comparing it to the exception handling clauses
    • LBYL, by contrast, incurs a potentially high fixed cost: the additional check is always performed, regardless of success or failure

    That then leads to the following decision criteria:

    • Is this piece of code known to be critical to the speed of the application? If not, then don't worry about which of the two is faster, worry about which of the two is easier to read.
    • Is the pre-check more expensive than the cost of raising and catching an exception? If yes, then EAFP is always faster and should be used.
    • Things get more interesting if the answer is "no". In that case, which is faster will depend on whether the success or the error case is more common, and the relative speeds of the pre-check and the exception handling. Answering this definitively requires real timing measurements.

    As a rough rule of thumb:

    • if there is a potential race condition, use EAFP
    • if speed isn't critical, just use whichever you consider easier to read
    • if the pre-check is expensive, use EAFP
    • if you expect the operation to succeed most of the time*, use EAFP
    • if you expect the operation to fail more than half the time, use LBYL
    • if in doubt, measure it

    *People will vary as to what they consider "most of the time" in this context. For me, if I expect the operation to succeed more than half the time, I would just use EAFP as a matter of course, until I had reason to suspect this piece of code was an actual performance bottleneck.

    这篇关于尝试/抓住或验证速度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆