多线程无法与Parallel Foreach一起使用

时间:2018-06-30 03:03:37

标签: c# multithreading

public void GetTopRequest()
{
        DataTable dtListofTransaction = new DataTable();
        string sconnection = ConfigurationManager.AppSettings[ConfigurationManager.AppSettings["BUToProcess"].ToString()].ToString();
        string query = "select Error_Counter, MembershipEnrollmentStatus_ID_PKID, outbound_xml, type_of_transaction, ProcessSet_GUID from MES where TP = 0 and RS = 'A' and type_of_transaction = 'Initial Enrollment'";

        using (SqlConnection sqlConn = new SqlConnection(sconnection))
        {
            sqlConn.Open();

            using (SqlCommand cmd = new SqlCommand(query, sqlConn))
            {
                dtListofTransaction.Load(cmd.ExecuteReader());
                var tmpdtListofTransaction = dtListofTransaction;

                if (dtListofTransaction.Rows.Count > 0)
                {
                    var distinctListOfFamilies = (from row in tmpdtListofTransaction.AsEnumerable()
                                                  select row.Field<Guid>("ProcessSet_GUID")).Distinct().ToList();
                    int countOfFamilies = distinctListOfFamilies.Count();
                    int FamiliesToBeProcessedByThread = (countOfFamilies > 50 ? (countOfFamilies / Convert.ToInt32(ConfigurationManager.AppSettings["ThreadsToUse"])) + 1 : countOfFamilies);
                    var listOfSubscriberLists = splitList<Guid>(distinctListOfFamilies, FamiliesToBeProcessedByThread);
                    var tmplistOfSubscriberLists = listOfSubscriberLists;

                    if (countOfFamilies > 0)
                    {
                        Parallel.ForEach(listOfSubscriberLists,, new ParallelOptions { MaxDegreeOfParallelism = 4}, ac => 
                        {
                            foreach (var guid in ac)
                            {
                                Console.WriteLine(guid + " : " + DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff"));
                                var dbMembersToProcess = tmpdtListofTransaction.AsEnumerable().Where(p => object.Equals(p["ProcessSet_GUID"], guid) && p["outbound_xml"] != null);

                                foreach (var member in dbMembersToProcess)
                                {
                                    PushWWRequest.SendTransactions(member["outbound_xml"].ToString(), member["type_of_transaction"].ToString(), member["MembershipEnrollmentStatus_ID_PKID"].ToString(), Convert.ToInt32(member["Error_Counter"].ToString()));
                                }
                            }
                        });
                    }
                }
            }

            sqlConn.Close();
        }
    }

    public static void SendTransactions(string sRequest, string sTransactionType, string sPKID = "", int ErrorCounter = 0)
    {
        switch (sTransactionType)
        {
            case TransactionType.INITIALENROLLMENT:
                try
                {
                    CMInitialCustomerSetupTypeClient svcInitialCustomerSetupClientProxy = ClientOrmbProxy<CMInitialCustomerSetupTypeClient>();
                    CMInitialCustomerSetup initialCustomerSetupRequest = Deserialize<CMInitialCustomerSetup>(sRequest);                   
                    svcInitialCustomerSetupClientProxy.CMInitialCustomerSetup(initialCustomerSetupRequest);
                }
                catch (System.ServiceModel.CommunicationException svcExcpt)
                {
                    print svcExcpt
                }
                break;
     }
 }

我试图一次使用4个线程(定义为上面的并行度设置为4)发送4个请求,以便在Parallel.ForEach循环中使用上述代码进行处理,但是我没有看到4个请求同时获取线程,并以随机顺序处理线程。我不确定我在做什么错。

任何建议都会有所帮助...谢谢。

1 个答案:

答案 0 :(得分:3)

由于您的问题相当琐碎,因此我会用其他一些建议来回答问题

  • 您不应该将Parallel.ForEach与IO绑定任务一起使用,浪费线程和资源,async await模式是一种更好的方法,它将释放线程回到操作系统,等待IO完成端口时,我认为ActionBlock是两全其美的选择。

  • 您的代码一团糟(以最好的方式表示)

  • MaxDegreeOfParallelism只是一个建议,而不是合同,TPL会决定需要什么并认为合适。

  • 如果并行运行,则不能保证将以什么顺序执行什么,即并行编程的思想,线程具有一定的自由度,不能保证顺序

  • 您正在各处创建参考副本,无需这样做,即var tmpdtListofTransaction = dtListofTransaction;

  • DataTable dtListofTransaction = new DataTable()应该在使用声明中

  • 减少嵌套的可读性,只是因为您可以将内容放入lambda语句中并不意味着您应该这样做,从而使自己更容易

  • 在嵌套语句中停止使用ConfigurationManager,这使得它无法读取,使用表达式的固定属性或一次将它们存储在变量中并完成操作

如果您想一次确保4个线程同时运行,请考虑使任务失效,并根据需要使用WaitAllWhenAll,可能是await Task.WhenAll(tasks);