全局对象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();
 }

全局对象vs多个新对象

你的问题是我需要优化代码吗?

总的来说,

  1. 如果它两个容易优化它,和代码仍然保持简单比做它,否则,如果不确定它是否会产生影响,那么就这样吧,
  2. 如果你不确定就测量
  3. 在相关代码附近留下评论

如何测量?您可以查看您的程序是否运行缓慢,或者是否使用了太多内存。

关于你的第二次编辑,

可以将foreach循环转换为LINQ,汇总所有的目录,然后一次添加目录到您的DB

你的代码将看起来更优雅,它将解决你的主要问题

参见http://www.linqtutorial.net/linqExamples.html有一段如何用LINQ替换迭代循环

这里的主要性能问题是您为查询的"准备"支付了多少费用。准备是解析查询和(更重要的)确定查询计划的地方。查询计划的确定可能非常昂贵,您希望最小化必须执行的次数。

(注意:即使DELETE ... WHERE ...从你的例子需要一个查询计划。)

一些dbms和ADO。. NET提供程序在"重用"查询计划方面优于其他提供程序。在Oracle/ODP。例如,如果您重复地重新创建您的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#代码和相关的垃圾收集压力。

我认为这里的关键建议是不要留下遗留的数据库连接,然后在临时的基础上打开和操作。我注意到你的问题实际上是围绕是否重用命令展开的——当你注意到你的连接必须已经是可重用的……我不建议这样做,而是建议您将每个数据库操作视为一个原子工作单元,包括连接利用率等。

最好使用第一种方法,以便执行查询的逻辑留在单个函数中。

我认为正确的版本在

public foo() 
{
   var context = generateContext(dir);
   context.excute();
}

把两个目标分开

  1. 创建上下文

在创建上下文中,use可以使用单例

我更喜欢使用全局变量,而不是每次操作都重新创建相同的对象。一次性分配成本很小,而每次迭代创建对象的成本可能很高。