在与Microsoft员工进行代码审查期间,我们在try{}块中遇到了大量代码.她和IT代表建议这可能会影响代码的性能.事实上,他们建议大多数代码应该在try/catch块之外,并且只应该检查重要的部分.微软员工补充说,即将发布的白皮书警告不要使用不正确的try/catch块.
我环顾四周,发现它可以影响优化,但它似乎只适用于范围之间共享变量.
我不是在询问代码的可维护性,甚至不是在处理正确的异常(有问题的代码需要重新分解,毫无疑问).我也没有提到使用流量控制的异常,这在大多数情况下显然是错误的.这些都是重要的问题(有些更重要),但不是重点.
如果不抛出异常,try/catch块如何影响性能?
想象一下代码:
public class obj
{
// elided
}
public static Dictionary<string, obj> dict = new Dictionary<string, obj>();
Run Code Online (Sandbox Code Playgroud)
方法1
public static obj FromDict1(string name)
{
if (dict.ContainsKey(name))
{
return dict[name];
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
方法2
public static obj FromDict2(string name)
{
try
{
return dict[name];
}
catch (KeyNotFoundException)
{
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
我很好奇这两个函数的性能是否存在差异,因为第一个函数应该比第二个函数更低 - 假设它需要在字典包含值时检查两次,而第二个函数确实只需要访问字典曾经但是WOW,它实际上是相反的:
循环1 000 000个值(现有10万个,不存在90 000个):
第一个功能:306毫秒
第二功能:20483毫秒
这是为什么?
编辑:你可以在下面这个问题的评论中注意到,如果有0个非现有密钥,第二个函数的性能实际上略好于第一个函数.但是,一旦存在至少一个或多个非现有密钥,则第二个密钥的性能会迅速下降.
我们已经看到很多关于何时以及为何使用try/ catch和try/ catch/的问题finally.我知道try/ 肯定有一个用例finally(特别是因为它是using语句实现的方式).
我们还看到了有关try/catch和异常开销的问题.
然而,我所链接的问题并没有谈到JUST try-finally的开销.
假设try块中发生的任何事情都没有异常,那么确保finally语句在离开try块时执行的开销是多少(有时是从函数返回)?
再一次,我只询问try/ finally,不catch,不抛出异常.
谢谢!
编辑:好的,我将尝试更好地展示我的用例.
我应该使用哪个,DoWithTryFinally或者DoWithoutTryFinally?
public bool DoWithTryFinally()
{
this.IsBusy = true;
try
{
if (DoLongCheckThatWillNotThrowException())
{
this.DebugLogSuccess();
return true;
}
else
{
this.ErrorLogFailure();
return false;
}
}
finally
{
this.IsBusy = false;
}
}
public bool DoWithoutTryFinally()
{
this.IsBusy …Run Code Online (Sandbox Code Playgroud) 寻找一种方法,以便在遇到一段代码时以编程方式转储调用堆栈和.net Win Forms应用程序.它之前我没有遇到过但会节省一些调试时间.
更新:忘记添加,这将增加应用程序的开销,即它会大大减慢它的速度.
我来自python背景,经常说道歉比要求许可更容易道歉.特别给出了两个片段:
if type(A) == int:
do_something(A)
else:
do_something(int(A))
try:
do_something(A)
except TypeError:
do_something(int(A))
Run Code Online (Sandbox Code Playgroud)
然后在大多数使用场景下,当A通常是一个整数时假设第二个会更快(假设do_something需要一个整数作为输入并且会相当迅速地提高它的异常),因为你从每个执行循环中丢失了逻辑测试,代价是更多昂贵的例外,但不那么频繁.
我想要检查的是在C#中这是否正确,或者逻辑测试与异常相比是否足够快以使其成为一个小角落?
哦,我只对发布性能感兴趣,而不是调试.
好吧,我的例子太模糊了试试这个:
天真的解决方案:
return float(A) % 20 # coerse A to a float so it'll only fail if we actually don't
# have anything that can be represented as a real number.
Run Code Online (Sandbox Code Playgroud)
逻辑解决方案:
if isinstance(A, Number): # This is cheaper because we're not creating a new
return A % 20 # object unless we really have to.
else:
return float(A) %20
Run Code Online (Sandbox Code Playgroud)
基于异常的解决方案:
try: # Now …Run Code Online (Sandbox Code Playgroud) 我正在尝试为我的游戏添加插件,我正在尝试实现的是:
插件将是我的或第三方的,所以我想要一个解决方案,插件崩溃不会意味着主应用程序崩溃.
插件的方法经常被调用(例如,因为绘制了游戏对象).
到目前为止我发现了什么:
1)http://www.codeproject.com/KB/cs/pluginsincsharp.aspx - 看起来应该很好用的简单概念.由于插件在我的游戏中用于每一轮,我只需要添加Restart()方法,如果不再需要插件,Unload()方法+ GC应该处理它.
2)http://mef.codeplex.com/Wikipage - 托管扩展框架 - 我的程序应该在.NET 3.5上工作,我不想单独添加任何其他框架我想自己编写我的插件系统.因此,这个解决方案是不可能的.
3)Microsoft提供:http://msdn.microsoft.com/en-us/library/system.addin.aspx但是根据我读过的一些文章它非常复杂.
4)插件的不同AppDomains.根据Marc Gravell(在C#中使用AppDomain),不同的AppDomain允许隔离.卸载插件很容易.性能负荷是多少?我需要经常调用插件的方法(例如绘制对象).
你能评论一下我的发现吗?新方法也受到欢迎!谢谢!
我的问题很模糊:o) - 但这是一个例子:
当我编写C代码时,我能够在出现故障时记录计数器的值:
<...>
for ( int i = 0 ; i < n ; i++ )
if ( SUCCESS != myCall())
Log( "Failure, i = %d", i );
<...>
Run Code Online (Sandbox Code Playgroud)
现在,使用异常,我得到这个:
try
{
<...>
for ( int i = 0 ; i < n ; i++ )
myCall();
<...>
}
catch ( Exception exception )
{
Log( "Failure ! Maybe in myCall() ? Don't know. i's value ? No clue." );
}
Run Code Online (Sandbox Code Playgroud)
当然,可以在try/catch语句之外声明"i"(这就是我正在做的事情).但我不喜欢它 - 我喜欢声明变量在哪里使用,而不是之前.
但也许我在这里遗漏了一些东西.你有什么优雅的解决方案吗?
预先感谢 !西尔万.
ADDED:myCall()是一个不起眼的API调用 …
我在数据访问层有一些功能
public Order RetrieveById(int id)
public List<Order> RetrieveByStatus(OrderStatus status)
Run Code Online (Sandbox Code Playgroud)
现在我对异常引发有点困惑。
对于 RetrieveById 函数,小于 1 的 id 是无效 id,因此我想引发异常。我想为数据库中不存在的 Id 返回 null。然后感觉我太复杂了。
对于 RetrieveByStatus,当数据库中没有该状态的数据时,我想返回一个空列表。
但是我看到有些人在 RetrieveById 无法返回任何内容时引发异常,但 RetrieveByStatus 在没有记录时不应引发异常,或者应该吗?
有人可以帮我澄清这些概念吗?
MSDN告诉我们,当你调用"File.Delete(path);"时 在不存在的文件上生成异常.
在执行删除之前调用delete方法并使用try/catch块来避免错误或验证文件的存在会更有效吗?
我倾向于认为避免try/catch块更好.当您知道如何检查错误时,为什么会发生错误.
无论如何,这里是一些示例代码:
// Option 1: Just delete the file and ignore any exceptions
/// <summary>
/// Remove the files from the local server if the DeleteAfterTransfer flag has been set
/// </summary>
/// <param name="FilesToSend">a list of full file paths to be removed from the local server</param>
private void RemoveLocalFiles(List<string> LocalFiles)
{
// Ensure there is something to process
if (LocalFiles != null && LocalFiles.Count > 0 && m_DeleteAfterTransfer == true)
{
foreach (string file in LocalFiles) …Run Code Online (Sandbox Code Playgroud) 可能重复:
.NET异常有多慢?
是否存在抛出异常并立即捕获的开销?这有什么区别
void DoSomething(object basic)
{
try
{
if (basic == null)
throw new NullReferenceException("Any message");
else
{
//...
}
}
catch (Exception error)
{
_logger.WriteLog(error);
}
}
Run Code Online (Sandbox Code Playgroud)
这个(这里我们不抛出异常):
void DoSomething(object basic)
{
try
{
if (basic == null)
{
_logger.WriteLog(new NullReferenceException("Any message");
return;
}
else
{
...
}
}
catch (Exception error)
{
_logger.WriteLog(error);
}
}
Run Code Online (Sandbox Code Playgroud)
第二个片段会更快吗?
此外,我想知道为什么一个解决方案比另一个更快.
我需要一个接一个地执行大量语句,并且我需要在sigle语句抛出异常时,程序流继续执行下一个语句,例如:
double a = Double.Parse("2.5");
double b = Double.Parse("ADFBBG");
Geometry g = Geometry.Parse("M150,0L75,200 225,200z");
Run Code Online (Sandbox Code Playgroud)
所有语句都必须执行,所以我需要一种级联的try-catch块:
double a, b;
Geometry g;
try
{
a = Double.Parse("2.5");
}
catch
{}
try
{
b = Double.Parse("ADFBBG");
}
catch
{}
try
{
g = Geometry.Parse("M150,0L75,200 225,200z");
}
catch
{}
Run Code Online (Sandbox Code Playgroud)
显然,这不是编写程序的最优雅方式.有更好的方法(更优雅,不会显着降低性能)?
我尝试Func<TResult>以这种方式使用委托:
我写了以下方法:
T Try<T>(Func<T> func)
{
try
{
return func();
}
catch
{
return default(T);
}
}
Run Code Online (Sandbox Code Playgroud)
所以我可以像这样使用它:
double x = Try(() => Double.Parse("77"));
Geometry g = Try(() => …Run Code Online (Sandbox Code Playgroud) 如果在一个班级A:
Class A
public List<string> getValues
Run Code Online (Sandbox Code Playgroud)
如果我想调用该方法,我应该总是检查返回值是否为空?虽然我不认为它可能是null(应该是一个空列表).即
Class B
public void GetSomething
foreach (var thing in A.getValues)
//do something....
Run Code Online (Sandbox Code Playgroud)
要么
Class B
public void GetSomething
var things = A.getValues;
if (things != null)
foreach (var thing in things)
//then doing something....
Run Code Online (Sandbox Code Playgroud)
提出这个问题的原因是,当我编写单元测试时,我在A类中使该方法返回null而不是空列表,但是如果它发生的话我在现实生活中不知道,因为如果它可以为null那么它总是好的检查而不是尝试捕获异常,哪一个更合适?
c# ×12
exception ×4
performance ×4
.net ×2
try-catch ×2
debugging ×1
dictionary ×1
file-io ×1
func ×1
null ×1
plugins ×1
python ×1
return-code ×1
try-finally ×1