Jes*_*sse 4 c# multithreading delegates
在下面的问题中,我发现了以类型安全的方式调用QueueUserWorkItem的巧妙技巧,您可以在其中传递委托而不是WaitCallBack和对象.但是,它并不像人们期望的那样工作.
QueueUserWorkItem()和BeginInvoke()之间的区别是什么,用于执行不需要返回类型的异步活动
以下是一些演示此问题的示例代码和输出.
for (int i = 0; i < 10; ++i)
{
// doesn't work - somehow DoWork is invoked with i=10 each time!!!
ThreadPool.QueueUserWorkItem(delegate { DoWork("closure", i); });
// not type safe, but it works
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), Tuple.Create(" WCB", i));
}
void DoWork(string s, int i)
{
Console.WriteLine("{0} - i:{1}", s, i);
}
void DoWork(object state)
{
var t = (Tuple<string, int>)state;
DoWork(t.Item1, t.Item2);
}
Run Code Online (Sandbox Code Playgroud)
这是输出:
closure - i:10
WCB - i:0
closure - i:10
WCB - i:2
WCB - i:3
closure - i:10
WCB - i:4
closure - i:10
WCB - i:5
closure - i:10
WCB - i:6
closure - i:10
WCB - i:7
closure - i:10
WCB - i:8
closure - i:10
WCB - i:9
WCB - i:1
closure - i:10
Run Code Online (Sandbox Code Playgroud)
请注意,当使用闭包调用QueueUserWorkitem时,i = 10表示永远调用,但在使用WaitCallBack时,您将获得正确的值0-9.
所以我的问题是:
在创建匿名方法时,您的两个问题的答案都与闭包的范围有关.
当你这样做:
// Closure for anonymous function call begins here.
for (int i = 0; i < 10; ++i)
{
// i is captured
ThreadPool.QueueUserWorkItem(delegate { DoWork("closure", i); });
}
Run Code Online (Sandbox Code Playgroud)
你捕捉i横跨整个循环.这意味着您可以非常快速地排队十个线程,并且当它们开始时,闭包已经捕获i为10.
为了解决这个问题,你可以通过在循环中引入一个变量来减少闭包的范围,如下所示:
for (int i = 0; i < 10; ++i)
{
// Closure extends to here.
var copy = i;
// **copy** is captured
ThreadPool.QueueUserWorkItem(delegate { DoWork("closure", copy); });
}
Run Code Online (Sandbox Code Playgroud)
这里,闭包不会延伸到循环之外,而只是延伸到内部的值.
也就是说,第二次调用会QueueUserWorkItem产生所需的结果,因为你Tuple<T1, T2>在委托排队的时候已经创建了,那么这个值是固定的.
请注意,在C#5.0中,行为foreach被更改,因为它经常发生(闭包关闭循环)并导致许多人头痛(但for不像你正在使用).
如果你想利用这个事实,你可以调用类上的Range方法来使用:Enumerableforeach
foreach (int i in Enumerable.Range(0, 10))
{
// Closure for anonymous function call begins here.
ThreadPool.QueueUserWorkItem(delegate { DoWork("closure", i); });
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3377 次 |
| 最近记录: |