文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>.Net 4.0并行库实用性演练

.Net 4.0并行库实用性演练

时间:2010-09-08  来源:小城故事

  前面说在练习Paralle时,发现另有乾坤,是这样的代码:

代码
static IEnumerable<Person> testFill()
{
var list
= new List<Person>(9);

Enumerable.Range(
1, 99999).ToList().ForEach(n =>
{
var name
= "Person" + n % 9;
list.Add(
new Person { Id = n, Name = name });
});
Console.WriteLine(
"Person's count is {0}", list.Count);
return list;
}

static IEnumerable<Person> testFillParallel()
{
var list
= new List<Person>(9);

Enumerable.Range(
1, 99999).AsParallel().ForAll(n =>
{
var name
= "Person" + n % 9;
list.Add(
new Person { Id = n, Name = name });
});
Console.WriteLine(
"Person's count is {0}", list.Count);
return list;
}

class Person
{
internal int Id { get; set; }
internal string Name { get; set; }
}

  结果是:

  Fill 方法:   35ms

  FillParallel 方法:  47ms

  怎么会多线程还不如单线程快,和上文例子比较一下,有点明白了。稍微改了下代码,在Add语句前加了个Thread.Sleep(1),迭代次数减为999,试了一次,结果是:

  Fill 方法:   1014ms

  FillParallel 方法:  522ms

  多个线程协同工作时,分配任务本身有开销,要是分配的开销比任务本身还大,多线程就没有意义了。就比如你交待别人做某件事,要是交待的功夫比自己做还长,还不如自己做。所以这里Sleep一下模拟长一点的单次处理过程。

  FillParallel方法,大家觉得有没有其它问题呢?想必一般人都能看出,这里有最初级的线程安全问题。没看出的应该是刚学.Net各种集合的初学者,线程安全还只是个太虚幻境。不过借助这个Parallel,就可以轻松神游幻境。把FillParallel方法循环一百次执行,会发现返回结果本来应该有999个元素,输出的却显示却结果经常少十几二十个。如果创建List时赋的容量不够,在List扩容时,还可能引发异常。不过一百次都是999也不是不可能,要看你的RP了。

  接着我改下逻辑,增加了一个是否Person存在重名的判断,变成:

代码
static IEnumerable<Person> testFillParallel()
{
var list
= new List<Person>(9);

Enumerable.Range(
1, 999).AsParallel().ForAll(n =>
{
var name
= "Person" + n % 9;
if (list.Count(p => p.Name == name) < 1) list.Add(new Person { Id = n, Name = name });
});
Console.WriteLine(
"Person's count is {0}", list.Count);
return list;
}

  RP不管用了,执行几次,必抛异常:System.InvalidOperationException: Collection was modified; enumeration operation may no execute.

  一个线程在枚举集合元素,这时必须保证集合不被其它线程修改,怎么办呢?以前,就知道用锁,现在据说有了线程安全的集合类,在System.Collections.Concurrent命名空间下,有ConcurrentDictionary, ConcurrentQueue, ConcurrentStack,就是没有ConcurrentList。费了半天,才发现与List对应的应该是BlockingCollection。

  把集合定义换成: var list = new BlockingCollection<Person>(9); 只见刷刷刷,就可以一路跑完了。

  不过这样做,还是会发现问题,不知大家看出了吗?

相关阅读 更多 +
排行榜 更多 +
立体反应点击

立体反应点击

休闲益智 下载
料理物语

料理物语

休闲益智 下载
滑杆优雅舞者

滑杆优雅舞者

休闲益智 下载