全局对象与多个新对象?
Posted
技术标签:
【中文标题】全局对象与多个新对象?【英文标题】:Global objects vs multiple new objects? 【发布时间】:2011-09-20 10:17:13 【问题描述】:假设我有一个方法,该方法需要在每次运行期间创建少量对象,并且该方法将被多次调用,即从数据库中删除给定行的方法。每次都创建一个新对象并调用垃圾收集器(或类似的)在最后销毁它,还是每次都重新初始化该值会更好吗?
示例: 每次都使用新的构造函数:
private void RemoveFolder(string dir)
OleDbCommand cmd2 = connection.CreateCommand();
OleDbParameter parameterC = new OleDbParameter();
cmd2.Parameters.Add(parameterC);
parameterC.Value = dir;
cmd2.CommandText = "DELETE * FROM [Directories] WHERE Path = ?";
cmd2.ExecuteNonQuery();
cmd2.Dispose();
使用单个全局变量(在构造函数中初始化):
private void RemoveFolder(string dir)
parameterC.Value = dir;
cmd2.CommandText = "DELETE * FROM [Directories] WHERE Path = ?";
cmd2.ExecuteNonQuery();
编辑:当我说得更好时,我的意思是在正常的非“关键任务”程序中“作为一个整体”,其中性能的大幅提升将胜过稳定性的小幅下降.
EDIT2
多次调用类似方法的示例
(注意这是我的另一种方法,AddFolder)
foreach (DirectoryInfo directory in directories)
parameter.Value = directory.FullName;
cmd.CommandText = "SELECT LastModified FROM Directories WHERE Path = ?";
reader = cmd.ExecuteReader();
while (reader.Read())
output += reader.GetString(0);
if (output == null)
Console.WriteLine("New Directory! " + directory.FullName);
AddFolder(directory);
output = null;
reader.Close();
【问题讨论】:
能否请您显示多次执行此方法的代码 【参考方案1】:您的问题是我需要优化该代码吗?
我的总体看法,
-
如果两个容易优化它,并且代码仍然比它简单,
否则,如果不确定它是否会产生影响而不是这样,
如果不确定,请测量它
在相关代码附近留下评论
如何测量它? 您可以查看您的程序是否运行缓慢,或者它是否使用了太多内存..
【讨论】:
【参考方案2】:关于您的第二次编辑,
您可以将 foreach 循环转换为 LINQ, 聚合所有目录,然后立即 将目录添加到您的数据库中
你的代码会看起来更优雅,它会解决你的主要问题
见http://www.linqtutorial.net/linqExamples.html有一段如何用LINQ替换迭代循环
【讨论】:
【参考方案3】:您在这里遇到的主要性能问题是您为查询的“准备”支付了多少费用。准备是解析查询和(更重要的是)确定查询计划的地方。查询计划的确定可能相当昂贵,您希望尽量减少必须完成的次数。
(注意:即使您示例中的 DELETE ... WHERE ...
也需要查询计划。)
某些 DBMS 和 ADO.NET 提供程序在“重用”查询计划方面比其他提供程序更好。例如,在 Oracle/ODP.NET 上,您是否反复重新创建 DbCommand
可能并不重要 - Oracle 将倾向于“看到”这是以前使用的相同查询并重用查询计划。
另一方面,如果您想确保查询准备一次并重复使用多次,无论您使用什么 DBMS,保持相同的 DbCommand
对象不是一个坏主意在整个应用程序执行过程中(甚至显式调用 DbCommand.Prepare
),如下所示:
var conn = new OracleConnection("your connection string"); // Or DB2Connection, SqlConnection or NpgsqlConnection or whatever...
conn.Open();
// Execute once:
var cmd = conn.CreateCommand();
cmd.CommandText = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = :your_param";
var param = cmd.CreateParameter();
param.ParameterName = "your_param";
param.DbType = ...;
cmd.Parameters.Add(param);
cmd.Prepare(); // Not really important for Oracle, but may be important for others.
// Execute multiple times:
param.Value = "some value";
int row_count = cmd.ExecuteNonQuery();
// If you are concerned with long-lived connections, you'll typically be able to do this:
conn.Close();
// ...
conn.Open();
param.Value = "some other value";
row_count = cmd.ExecuteNonQuery();
// Etc..
所以:
如果您的程序仅在单个 DBMS/ADO.NET 提供程序上运行,并且您知道它将有效地重用查询计划,并且您不介意稍微昂贵的 C# 代码,那么您可能会选择“重复重新创建”解决方案。它还可能允许稍微短一点的 C# 代码。 但是,我更喜欢“创建一次,多次重复使用”的解决方案 - 无论我使用什么 DBMS,我都会获得最佳性能。即使在那些智能到足以重用查询计划的 DBMS 下,我仍然会避免重新执行 C# 代码和相关的垃圾收集压力。【讨论】:
【参考方案4】:我认为这里的关键建议是不要留下挥之不去的数据库连接,然后在临时基础上打开和操作。我注意到您的问题实际上围绕是否重用命令 - 当,在查看时,注意到您的连接必须已经是可重用的......我不建议这样做,并建议您将每个数据库操作视为一个原子单元工作量,包括连接利用率等。
【讨论】:
我通常会完全同意你的看法。但是,在扫描更改后连接会关闭(当前为 10 秒)。每次编辑都重新打开连接太慢而无法使用【参考方案5】:最好使用第一种方法,这样执行查询的逻辑就停留在单个函数中。
【讨论】:
【参考方案6】:我认为正确的版本介于两者之间
public foo()
var context = generateContext(dir);
context.excute();
把两个目标分开
-
创建上下文
执行它
在创建上下文中使用可以使用单例
【讨论】:
【参考方案7】:我更喜欢使用全局变量,而不是每次操作都重新创建相同的对象。 一次性分配成本很小,而每次迭代创建对象的成本可能很高。
【讨论】:
这是我的想法。然而,我有幸见到的每个开发人员都表示,全局变量(或对象)一般来说是个坏消息。因此我的困境......以上是关于全局对象与多个新对象?的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript之jQuery-9 jQuery 开发插件(添加新全局函数添加jQuery对象方法添加新简写方法方法参数)