在C#中等待连接的最佳方式是什么?

6

我正在审查我正在工作的一个应用程序中连接到数据库的代码,并看到了这个:

 if (_dbConnection == null)
     _dbConnection = GetConnection();

 while (_dbConnection.State == ConnectionState.Connecting)
 {
     //Do Nothing until things are connected.
 }

 if (_dbConnection.State != ConnectionState.Open)
     _dbConnection.Open();

 var command = GetCommand(commandType);
 command.Connection = _dbConnection;
 return command;

这个while循环让我有点担心。有没有更好的方法来等待连接成功之前什么都不做?

编辑:

连接是通过以下方式获取的

private static IDbConnection GetConnection()
{
     return new SqlConnection(ConfigurationManager.ConnectionStrings["CoonectionStringName"].ConnectionString);
}

2
什么类型的连接?System.Data.SqlClient.SqlConnection? - agent-j
1
我会设置一个超时时间,并在while循环中加入延迟/等待语句,这样就不会浪费CPU时间。 - Earlz
我真的不知道这两者之间的区别。我想我可以。 - Carlos Blanco
如果您使用IDbConnection,则会错过DbConnection类指定的StateChange事件。 - Chandu
这个方法看起来像是在批处理中使用的,或者它似乎试图优化开放连接的使用。连接何时关闭? - Kit
显示剩余2条评论
4个回答

6
虽然循环确实可行且是等待某些后台操作的有效策略,但其他回答似乎忽略了一个关键点:你必须让后台操作做一些工作。反复执行 while 循环并不是非常有效,但 Windows 会认为应用程序的主线程(可能正在等待)非常重要,并在后台操作获得单个时钟周期之前,会旋转数百或数千次。
为了避免这种情况,使用 Thread.Yield() 语句告诉处理器旋转所有等待 CPU 时间的其他线程,并在它们完成后返回。这样,计算机可以在您等待后台进程的同时完成一些工作,而不是独占 CPU 来旋转基本上是空的循环。这很简单;以下是经过修订的 Justin 的答案:
var startTime = DateTime.Now;
var endTime = DateTime.Now.AddSeconds(5);
var timeOut = false;

while (_dbConnection.State == ConnectionState.Connecting)
{
    if (DateTime.Now.CompareTo(endTime) >= 0)
    {
        timeOut = true;
        break;
    }
    Thread.Yield(); //tells the kernel to give other threads some time
}

if (timeOut)
{
    Console.WriteLine("Connection Timeout");
    // TODO: Handle your time out here.
}

2

编辑:请注意,此方法适用于DbConnection而非IDbConnection

您可以始终使用DbConnection类的StateChange事件来代替while循环。

请查看此链接


只是在想,如果连接永远不到来会怎么样?事件就永远不会触发吗? - Carlos Blanco
@tou:这应该通过单独处理连接超时异常来解决... - Chandu
不知道 GetConnection() 的实现方式(例如,它可能是一个缓存连接的静态方法),上面代码的多次调用可能会执行 _connection.StateChange += (s, e) => {....},这可能导致在每个连续调用时调用更多的处理程序。 - Kit
如果连接确实是通过静态方法获取的,则需要完全不同的分析... - Chandu
连接的获取如下所示,返回 new SqlConnection(ConfigurationManager.ConnectionStrings["ConnStringName"].ConnectionString); - Carlos Blanco
显示剩余4条评论

1

考虑到这是一个Web应用程序,最好的做法是计算自开始尝试连接以来经过的时间,并在超时期限内退出。显然,在那一点上抛出异常或处理情况。

var startTime = DateTime.Now;
var endTime = DateTime.Now.AddSeconds(5);
var timeOut = false;

while (_dbConnection.State == ConnectionState.Connecting)
{
    if (DateTime.Now.Compare(endTime) >= 0
    {
        timeOut = true;
        break;
    }
}

if (timeOut)
{
    // TODO: Handle your time out here.
}

在这种情况下,while循环仍在运行并占用大量的处理器时间。 - Carlos Blanco

0

在StateChange事件上挂接一个处理程序。 当状态为Open时,执行所需操作。

            m_SqlConnection = new SqlConnection(ConnectionStringBuilder.ConnectionString);
            m_SqlConnection.StateChange += new System.Data.StateChangeEventHandler(m_SqlConnection_StateChange);
            m_SqlConnection.Open();



    void m_SqlConnection_StateChange(object sender, System.Data.StateChangeEventArgs e)
    {
        try
        {
            if (m_SqlConnection.State == ConnectionState.Open)
            {
                //do stuff
            }
            if (m_SqlConnection.State == ConnectionState.Broken)
            {
                Close();
            }
            if (m_SqlConnection.State == ConnectionState.Closed)
            {
                Open();
            }
        }
        catch
        {

        }
    }

我不建议这样做,因为每个状态更改都在不同的线程上运行,当从不同的线程使用连接时可能会导致不一致性。 - Idan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接