【问题标题】:ADONET async execution - connection broken errorADONET 异步执行 - 连接断开错误
【发布时间】:2015-03-22 07:29:22
【问题描述】:

我正在尝试异步查询执行一段时间。我的目标是执行简单的 SQL 语句,而不是等待它们完成。以下代码适用于 10、500 或 1000 甚至 5000 个查询。但是对于 50000 个查询,突然出现错误并说

“BeginExecuteReader 需要一个打开且可用的连接。连接的当前状态是打开的。” 有时它会说“......状态是:坏了”

这是 aspnet 测试站点,我认为可能会发生 50.000 个查询。是我错过了什么吗?它不应该工作吗?

我使用 windows7 x64,我相信它与 sql 连接轮询限制有关。你可能会说 50.000 太高了,但我需要避免这个错误以信任代码,我不知道如何。

ps:在代码中,我打开了连接,但没有出于测试目的关闭它。如果我关闭连接回调函数永远不会触发。

有什么建议吗?而且google上关于这个错误的信息并不多。

Partial Class test
    Inherits System.Web.UI.Page

    Dim cnTest As SqlConnection

    Protected Sub cmdAsyncTest_Click(sender As Object, e As EventArgs) Handles cmdAsyncTest.Click

        Dim s As String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        Dim sqlstr As String
        Dim x1 As Integer, x2 As Integer, i As Integer

        sqlstr = "INSERT INTO test1 (name,surname,a2) VALUES ('" & s & "','" & s & "',5)"

        Dim cnstr As String = System.Configuration.ConfigurationManager.ConnectionStrings("ConnectionStringLOG").ConnectionString
        cnTest = New SqlConnection(cnstr)
        cnTest.Open()

        watch = Stopwatch.StartNew()
        For i = 0 To 50000
            myExecute_Async(sqlstr)
        Next

    End Sub

    Function myExecute_Async(ByVal sqlstr As String) As String
            Using cmd As New SqlCommand(sqlstr, cnTest)
                cmd.CommandType = CommandType.Text
                cmd.BeginExecuteReader(New AsyncCallback(AddressOf QueryCallback), cmd)
                Return ""
            End Using
    End Function

    Sub QueryCallback(ByVal async As IAsyncResult)
        ' ToDo: something 
    End Sub

End Class



CREATE TABLE [dbo].[test1](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [name] [varchar](50) NULL,
    [surname] [varchar](50) NULL,
    [a2] [int] NULL,
 CONSTRAINT [PK_test1] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

“.NET SqlConnection 类、连接池和重新连接逻辑”一文不是答案。我的问题是异步执行。

我尝试使用该代码。我尝试不使用 sun 例程:

Dim cnstr As String = System.Configuration.ConfigurationManager.ConnectionStrings("ConnectionStringLOG").ConnectionString
cnTest = New SqlConnection(cnstr)
cnTest.Open()

watch = Stopwatch.StartNew()

For i = 0 To 50000
    Using cmd As New SqlCommand(sqlstr, cnTest)
        '  Return "" & cmd.ExecuteNonQuery()
        cmd.CommandType = CommandType.Text
        cmd.BeginExecuteReader(New AsyncCallback(AddressOf QueryCallback), cmd)
    End Using
Next

这次我抛出了“System.OutOfMemoryException”类型的异常。在 cmd.BeginExecuteReader 行。

假设我有需要运行这 50.000 条命令的逻辑。我应该怎么做才能避免内存问题或池限制?

【问题讨论】:

  • 这就是我首先尝试的。但是在 myExecute_Async 结束时,当您关闭连接(或不使用)时,连接将从内存中消失,并且不会调用回调函数。很奇怪,但您也没有收到任何错误消息。回调函数根本没有命中。
  • 抱歉,“.NET SqlConnection 类、连接池和重新连接逻辑”一文不是答案。我的问题是异步执行。无论如何,谢谢。
  • 你还在使用同一个连接...
  • 我尝试通过“使用”命令在子程序中打开连接。在那种情况下,异步执行对我来说失去了所有优势。速度与同步执行相同。甚至更长。 5000 个同步命令需要 26 秒,5000 个异步命令需要 32 秒。
  • 是的,不要那样做,我误读了你的问题。我建议你改用TPL。如果您使用 VS >= 12,请使用 Async and Await 关键字。

标签: asp.net sql-server vb.net asynchronous


【解决方案1】:

对于那些尝试处理繁重事务或对主题感兴趣的人:

最好的选择是hangfire。我也尝试了线程,它可以工作,但我认为我们的 hangfire 更简单,你不需要担心 web 池重启,任何事情都可能停止 IIS 服务,比如错误......

我调用了一个向 sql server 插入 10.000 条记录的类,并在 for..next 中调用了 100 次。肯定花了很长时间,但它就像一个魅力。我也杀死了 IIS 进程,然后一切都停止了。当我再次启动 IIS 时,一切都从应有的位置继续进行。

我更喜欢这个解决方案。

谢谢。

【讨论】:

    【解决方案2】:

    经过多次试验,我发现了这些:(可能我知识不够)

    异步 ​​SQL 查询执行很困难。如果您破坏连接对象,您将无法轻松捕获错误,您将无法触发异步回调函数。

    显然,它的设计目的不是一次执行 50.000 个查询。如果你认为这不会发生在现实生活中,我不反对。

    我使用了简单的解决方案:

       HostingEnvironment.QueueBackgroundWorkItem(Function(token) myTestClass.myExecute_Async(sqlstr, token))
    

    for...next 语句中有 50.000 个查询,执行时间为零秒。当然他们在排队,我查看了 sql 表,每次运行 SELECT COUNT(1) FROM test1 时,我的记录数都会增加近 1 分钟。它插入的记录数是exactlu 50.001(我从零开始盯着下一个),我觉得它更可靠。至少我了解幕后发生的事情。 IIS 内存使用量超过 114.000k 并正常返回到 19.000k。

    我希望这可以在某个时候对其他人有所帮助。

    感谢我的朋友。

    【讨论】:

    • 更好的解决方案是不要一次发出所有 50k 语句,而是在 N 需要试验的 N 线程上处理它们(可能接近内核数)。
    • 是的,QueueBackgroundWorkItem 就是这样做的。我知道 50.000 个查询很高,但我需要知道框架在此负载下的作用。
    • 同一进程中的所有其他工作将被淹没。网站的其余部分将停止。这不是一个好的解决方案。
    • 是的,我的朋友,你是对的。我明白了。由于这是对现实世界中大量交易的测试,我得到了教训。正如你所说,线程看起来是唯一合乎逻辑的解决方案,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    相关资源
    最近更新 更多