简体   繁体   English

ASP.NET应用程序中任务的奇怪行为

[英]Weird behaviour of task in ASP.NET application

I'm trying to connect and recieve very small amount of data from Mysql servers from all branches asynchronously, without waiting one to finish. 我试图异步地从所有分支的Mysql服务器连接并接收非常少量的数据,而不必等待一个完成。

I have my own event-driven .NET MySQL Connector Wrapper library and it works fine without asynchronously. 我有我自己的事件驱动的.NET MySQL Connector Wrapper库,它可以正常工作而无需异步。

Looks like I'm missing something while multi-tasking but I could not figured why. 看起来我在执行多任务处理时缺少某些东西,但我不知道为什么。

public void GetALL()
    {
        TaskList = new Task[RemSQL.Count];

        Response.Write("<h1>starting..........</h1>");

        Task t;
        BranchInfo b;
        Wrapper w;

        for (int tx = 0; tx < RemSQL.Count; tx++)
        {
            int txx = tx; //strongly suggested on MSDN while using tasks/threads in loops
            b = RemSQL[txx];
            w = b.Wrapper;
            Response.Write("<h2>TASK #" + txx.ToString() + " branch.id #" + w.id + " starts...</h2>");

            w.Connecting += Wrapper_Connecting;            
            w.Connected += Wrapper_Connected;
            w.ConnectionError += Wrapper_ConnectionError;

            //w.Connect() //disabling multitasking works just fine

            t = new Task(() =>
            {
                w.Connect();
            });

            TaskList[txx] = t;
            t.Start();

        }

        Task.WaitAll(TaskList);

        Response.Write("<h1>Tasks completed</h1>");

        foreach(BranchInfo bb in RemSQL)
        {
            bb.Wrapper.Dispose();
        }

        Response.Flush();
        Response.End();

    }

    private void Wrapper_Connected(object sender)
    {
        Wrapper w = (Wrapper)sender;
        WriteScript("Connected('" + w.id + "');");
    }

    private void Wrapper_Connecting(object sender)
    {
        Wrapper w = (Wrapper)sender;
        WriteScript("Connecting('" + w.id + "');");
    }

    private void Wrapper_ConnectionError(object sender, Exception ex)
    {
        Wrapper w = (Wrapper)sender;
        WriteScript("ConnectionFailed('" + w.id + "', '" + ex.Message + "');");
    }

private void WriteScript(string scr)
{
    Response.Write("<script>" + scr + "</script>\n");
    Response.Flush();
}

And here is the output: 这是输出:

<h1>starting..........</h1><h2>TASK #0 branch.id #2 starts...</h2>
<h2>TASK #1 branch.id #3 starts...</h2>
<h2>TASK #2 branch.id #4 starts...</h2>
<h2>TASK #3 branch.id #5 starts...</h2>
<h2>TASK #4 branch.id #6 starts...</h2>
<h2>TASK #5 branch.id #7 starts...</h2>
<h2>TASK #6 branch.id #8 starts...</h2>
<h2>TASK #7 branch.id #9 starts...</h2>
<h2>TASK #8 branch.id #10 starts...</h2>
<h2>TASK #9 branch.id #11 starts...</h2>
<h2>TASK #10 branch.id #13 starts...</h2>
<h2>TASK #11 branch.id #14 starts...</h2>
<h2>TASK #12 branch.id #15 starts...</h2>
<h2>TASK #13 branch.id #16 starts...</h2>
<h2>TASK #14 branch.id #17 starts...</h2>
<h2>TASK #15 branch.id #19 starts...</h2>
<h2>TASK #16 branch.id #20 starts...</h2>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>Connecting('20');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>Connected('20');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>ConnectionFailed('20', 'There is already an open DataReader associated with this Connection which must be closed first.');</script>
<script>Connected('20');</script>
<h1>Tasks completed</h1>

As you can see, I guess it looks like the Wrapper w always gets the reference of the last call in loop. 如您所见,我想包装器w总是会得到循环中最后一次调用的引用。 But when I comment out the tasking part and use w.Connect() directly in the loop, it all fixes up. 但是,当我注释掉任务部分并直接在循环中使用w.Connect()时,一切都已修复。

Any ideas ? 有任何想法吗 ?

Your problem is that you're closing over local variable w which you're changing later, so, by the time you got to the task it already contains other value that was at the time of running. 您的问题是您正在关闭稍后要更改的局部变量w ,因此,当您执行任务时,它已经包含运行时的其他值。

And solution is simple: declare t , b and w inside the loop. 解决方案很简单:在循环内声明tbw In fact, if I were you, I'd have rewritten it into simple Select : 实际上,如果我是您,我会将其重写为简单的Select

Response.Write("<h1>starting..........</h1>");
Task.WaitAll(
  RemSQL.Select(b => b.Wrapper).Select(w => TaskFactory.Run(() => {
        Response.Write("<h2>TASK #" + txx.ToString() + " branch.id #" + w.id + " starts...</h2>");

        w.Connecting += Wrapper_Connecting;            
        w.Connected += Wrapper_Connected;
        w.ConnectionError += Wrapper_ConnectionError;

        w.Connect();
  })).ToArray());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM