比较递归和异常的速度-Python

比较递归和异常的速度-Python,python,performance,exception,recursion,compare,Python,Performance,Exception,Recursion,Compare,首先,我必须为我的英语不好说声抱歉,但我已经尽力了 我有一个关于比较python中使用递归和异常计算阶乘的速度的练习 我写了一段代码: class MyException(Exception): def __init__(self, value): self.value = value def standardFactorial(n): if n == 1: return 1 return n * standardFactorial(n-

首先,我必须为我的英语不好说声抱歉,但我已经尽力了

我有一个关于比较python中使用递归和异常计算阶乘的速度的练习

我写了一段代码:

class MyException(Exception):
    def __init__(self, value):
        self.value = value

def standardFactorial(n):
    if n == 1:
        return 1
    return n * standardFactorial(n-1)

def factorialWithExceptions(n):
    if n == 1:
        raise MyException(1)
    try:
        factorialWithExceptions(n-1)
    except MyException as x:
        raise MyException(n * x.value)
对300的阶乘运行10000次,结果如下:

recursion
1.233912572992267
exceptions
9.093736120994436
有人能解释一下为什么差别这么大吗? python中的异常如此缓慢?或者问题出在哪里?构建异常堆栈?
感谢您的回复。

例外情况应适用于“例外”情况。Python的实现应该比Java轻一些,这导致Python方法倾向于比Java方法更频繁地使用异常(有一句格言:请求原谅比请求允许更好)。即便如此,在几乎所有的语言中,使用异常进行流控制都是不受欢迎的,因为这使得对代码进行推理变得更加困难,同时也因为创建异常、捕获异常、释放所有位并继续操作会对性能造成影响

话虽如此,为了进行比较,我测试了java等价物(使用BigInteger,因为只使用int会导致阶乘(300)的无意义结果).第一次,我得到了非常奇怪的结果,我将不得不看一看,但是更新代码在同一个应用程序中同时做这两件事,并进行一些检查,希望确保我们不会因为优化等而得到虚假结果:

import java.math.BigInteger;


class BigIntegerHolder extends Exception
{
    public BigInteger bigInt;
    public BigIntegerHolder(BigInteger x) { this.bigInt = x; }
}

class Factorial
{

    public static BigInteger fact(int n)
    {
        if (n == 1)
            {
                return BigInteger.valueOf(1);
            }
        return fact(n-1).multiply(BigInteger.valueOf(n));
    }



    public static void factExcept(int n) throws BigIntegerHolder
    {
        if (n == 1)
            {
                throw new BigIntegerHolder(BigInteger.valueOf(1));
            }
        try {
            factExcept(n-1);
        }
        catch (BigIntegerHolder ex)
            {
                throw new BigIntegerHolder( ex.bigInt.multiply(BigInteger.valueOf(n)));
            }
    }


    public static void main(String args[])
    {
        BigInteger realValue = fact(300);
        int count = 0;

        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++)
            {
                try {
                factExcept(300);
                }
                catch (BigIntegerHolder ex)
                    {
                        if (realValue.equals(ex.bigInt))
                            {
                                count += 1;
                            }
                    }

            }
        long end = System.currentTimeMillis();
        System.out.println("We got it right " + count + " times in " + (end - start) + " ms");


       count = 0;
        start = System.currentTimeMillis();
        for (int j = 0; j < 10000; j++)
            {
                BigInteger x = fact(300);
                if (realValue.equals(x))
                    {
                        count += 1;
                    }
            }
        end = System.currentTimeMillis();
        System.out.println("We got it right " + count + " times in " + (end - start) + " ms");

    }
}
import java.math.biginger;
类BigIntegerHolder扩展了异常
{
公共bigInt;
公共BigIntegerHolder(BigInteger x){this.bigInt=x;}
}
类阶乘
{
公共静态BigInteger事实(int n)
{
如果(n==1)
{
返回BigInteger.valueOf(1);
}
返回事实(n-1).multiply(BigInteger.valueOf(n));
}
公共静态void factException(int n)抛出较大整数
{
如果(n==1)
{
抛出新的BigInteger文件夹(BigInteger.valueOf(1));
}
试一试{
(n-1);
}
捕获(BigIntegerHolder ex)
{
抛出新的BigIntegerHolder(例如bigInt.multiply(BigInteger.valueOf(n));
}
}
公共静态void main(字符串参数[])
{
BigInteger实值=事实(300);
整数计数=0;
长启动=System.currentTimeMillis();
对于(int i=0;i<10000;i++)
{
试一试{
(300);
}
捕获(BigIntegerHolder ex)
{
if(realValue.equals(ex.bigInt))
{
计数+=1;
}
}
}
long end=System.currentTimeMillis();
println(“我们做对了”+“在”+(结束-开始)+“毫秒”中计数+”次);
计数=0;
start=System.currentTimeMillis();
对于(int j=0;j<10000;j++)
{
大整数x=事实(300);
if(realValue.equals(x))
{
计数+=1;
}
}
end=System.currentTimeMillis();
println(“我们做对了”+“在”+(结束-开始)+“毫秒”中计数+”次);
}
}
这将产生:

我们在23708毫秒内成功了10000次

我们在271毫秒内成功了10000次


(这表明在Java中,处理异常的速度几乎要慢100倍)

在第二个示例中,您使用的是递归和异常。