全局对象vs多个新对象
本文关键字:对象 新对象 vs 全局 | 更新日期: 2023-09-27 18:09:11
假设我有一个方法,它需要在每次运行期间创建少量对象,并且该方法将被多次调用,即从数据库中删除给定行的方法。每次创建一个新对象并调用垃圾收集器(或类似的)在结束时销毁它,还是每次重新初始化值更好?
例子:
每次使用新的构造函数:
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();
}
EDIT:我所说的"更好"是指在正常的非"关键任务"程序中的"整体",在这种情况下,性能的大幅提高将胜过稳定性的小幅下降。
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();
}
你的问题是我需要优化代码吗?
总的来说,
- 如果它两个容易优化它,和代码仍然保持简单比做它,否则,如果不确定它是否会产生影响,那么就这样吧,
- 如果你不确定就测量
- 在相关代码附近留下评论
如何测量?您可以查看您的程序是否运行缓慢,或者是否使用了太多内存。
关于你的第二次编辑,
可以将foreach循环转换为LINQ,汇总所有的目录,然后一次添加目录到您的DB
你的代码将看起来更优雅,它将解决你的主要问题
参见http://www.linqtutorial.net/linqExamples.html有一段如何用LINQ替换迭代循环
这里的主要性能问题是您为查询的"准备"支付了多少费用。准备是解析查询和(更重要的)确定查询计划的地方。查询计划的确定可能非常昂贵,您希望最小化必须执行的次数。
(注意:即使DELETE ... WHERE ...
从你的例子需要一个查询计划。)
一些dbms和ADO。. NET提供程序在"重用"查询计划方面优于其他提供程序。在Oracle/ODP。例如,如果您重复地重新创建您的DbCommand
,这可能无关紧要—Oracle将倾向于"看到"这是之前使用的相同查询并重用查询计划。
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#代码和相关的垃圾收集压力。
我认为这里的关键建议是不要留下遗留的数据库连接,然后在临时的基础上打开和操作。我注意到你的问题实际上是围绕是否重用命令展开的——当你注意到你的连接必须已经是可重用的……我不建议这样做,而是建议您将每个数据库操作视为一个原子工作单元,包括连接利用率等。
最好使用第一种方法,以便执行查询的逻辑留在单个函数中。
我认为正确的版本在
public foo()
{
var context = generateContext(dir);
context.excute();
}
把两个目标分开
- 创建上下文
在创建上下文中,use可以使用单例
我更喜欢使用全局变量,而不是每次操作都重新创建相同的对象。一次性分配成本很小,而每次迭代创建对象的成本可能很高。