C#Parallel.Foreach不对列表中的所有项执行操作

时间:2017-09-19 14:08:19

标签: c# parallel.foreach

    public static void RemoveAllNetworkPrinters()
    {
        ManagementScope oManagementScope = new ManagementScope(ManagementPath.DefaultPath);
        oManagementScope.Connect();

        SelectQuery oSelectQuery = new SelectQuery();
        oSelectQuery.QueryString = @"SELECT * FROM Win32_Printer WHERE ServerName IS NOT NULL";

        using (ManagementObjectSearcher oObjectSearcher = new ManagementObjectSearcher(oManagementScope, oSelectQuery))
        {
            using (ManagementObjectCollection oObjectCollection = oObjectSearcher.Get())
            {
                if (oObjectCollection.Count != 0)
                {
                    foreach (ManagementObject oItem in oObjectCollection)
                    {
                        oItem.Delete();

                    }
                }
            }
        }
    }

    public static void RemoveAllNetworkPrintersParallel()
    {
        ManagementScope oManagementScope = new ManagementScope(ManagementPath.DefaultPath);
        oManagementScope.Connect();

        SelectQuery oSelectQuery = new SelectQuery();
        oSelectQuery.QueryString = @"SELECT * FROM Win32_Printer WHERE ServerName IS NOT NULL";

        using (ManagementObjectSearcher oObjectSearcher = new ManagementObjectSearcher(oManagementScope, oSelectQuery))
        {
            using (ManagementObjectCollection oObjectCollection = oObjectSearcher.Get())
            {
                if (oObjectCollection.Count != 0)
                {
                    Parallel.ForEach(oObjectCollection.OfType<ManagementObject>().ToList(), oItem =>
                    {
                        oItem.Delete();
                    });
                }
            }
        }
    }

我有一个问题,参考c#中的Parallel.Foreach。我一直在测试并看到一些奇怪的例子我提供测试目的。当我执行此功能的非并行版本时,它工作正常,但是当我在1-2个项目之间的任何地方执行并行版本时,我不会在列表中处理。我已经阅读了msdn文档但是必须在这里遗漏一些东西。我知道您无法保证订单商品会被处理,但我们认为保证所有商品都会在清单中处理?任何帮助理解或我做错了将不胜感激。谢谢

1 个答案:

答案 0 :(得分:1)

正如评论中所讨论的,ManagementObject.Delete()不是线程安全的操作,因此不应该在不同的线程中使用它 MSDN

  

此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。

但是如果你真的需要这样做而你想在那里使用lock,你可以像这样做smthg

var lockObject = new Object();

Parallel.ForEach(/*.....*/, item =>
{
    lock (lockObject)
    {
        // do your magic here
    }
});

但正如我所说使用此代码是没有意义的,因为它会比ordinal foreach 慢。

所以,我的建议 - 只使用foreach。