开门见山,下面的例子中通过调用ThreadPool.QueueUserWorkItem(WaitCallback callBack, object state)的方式实现异步调用:
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: List<Action> actions = new List<Action>();
6: actions.Add(() => Console.WriteLine("A1"));
7: actions.Add(() => Console.WriteLine("A2"));
8: actions.Add(() => Console.WriteLine("A3"));
9: actions.Add(() => Console.WriteLine("A4"));
10:
11: foreach (var action in actions)
12: {
13: ThreadPool.QueueUserWorkItem(state => action(), null);
14: }
15:
16: Console.Read();
17: }
18: }
但是出现错误的输出结果:
解决的方案就是在每次For循环中,调用Thread.Sleep休眠当前线程,哪怕是1ms:
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: List<Action> actions = new List<Action>();
6: actions.Add(() => Console.WriteLine("A1"));
7: actions.Add(() => Console.WriteLine("A2"));
8: actions.Add(() => Console.WriteLine("A3"));
9: actions.Add(() => Console.WriteLine("A4"));
10:
11: foreach (var action in actions)
12: {
13: ThreadPool.QueueUserWorkItem(state => action(), null);
14:
15: Thread.Sleep(1);
16: }
17:
18: Console.Read();
19: }
20: }
21:
这次能够输出正确的结果:
我们也看到很多人确实是这么做的。但是如果真是必须这样的话,这样的编程方式很难让我接受,不知道大家有何高见。
在老赵的提示下,醒悟过来:由于被置于ThreadPool中的操作时异步的,还没有来的执行的时候,action已经被for循环改变,永远是同一个action对象! 呵呵,脑袋有时候有点转不过弯!
所以正确的写法是:
1: foreach (var action in actions)
2: {
3: var a = action;
4: ThreadPool.QueueUserWorkItem(state => a(), null);
5: }
作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。