ASP.NET 应用程序中任务的异常行为
Weird behaviour of task in ASP.NET application
我正在尝试从所有分支机构的 Mysql 服务器异步连接并接收非常少量的数据,无需等待一个完成。
我有自己的事件驱动 .NET MySQL Connector Wrapper 库,无需异步即可正常工作。
看起来我在处理多项任务时遗漏了一些东西,但我不明白为什么。
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();
}
这是输出:
<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>
如您所见,我猜 Wrapper w 似乎总是在循环中获取最后一次调用的引用。但是当我注释掉任务部分并直接在循环中使用 w.Connect() 时,一切都会修复。
有什么想法吗?
您的问题是您正在关闭局部变量 w
,稍后您将对其进行更改,因此,当您执行任务时,它已经包含 运行.
解决方案很简单:在循环内声明 t
、b
和 w
。事实上,如果我是你,我会把它重写成简单的 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());
我正在尝试从所有分支机构的 Mysql 服务器异步连接并接收非常少量的数据,无需等待一个完成。
我有自己的事件驱动 .NET MySQL Connector Wrapper 库,无需异步即可正常工作。
看起来我在处理多项任务时遗漏了一些东西,但我不明白为什么。
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();
}
这是输出:
<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>
如您所见,我猜 Wrapper w 似乎总是在循环中获取最后一次调用的引用。但是当我注释掉任务部分并直接在循环中使用 w.Connect() 时,一切都会修复。
有什么想法吗?
您的问题是您正在关闭局部变量 w
,稍后您将对其进行更改,因此,当您执行任务时,它已经包含 运行.
解决方案很简单:在循环内声明 t
、b
和 w
。事实上,如果我是你,我会把它重写成简单的 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());