List <t>中的C#Parallel.Foreach int []未正确更改

时间:2018-09-08 13:47:51

标签: c# parallel.foreach

这是我的课程:

public class UnusedRolesOccurrence
{
    public string Username { get; set; }
    public string FullName { get; set; }
    public string Role { get; set; }
    public int[] Month { get { return month; } set { month = value; } }
    private static int[] month = new int[12];
}

这是我要在int数组中填充值的地方:

Parallel.ForEach(unusedrolesoccurrence, (UnusedRolesOccurrence item) =>
{
    try
    {
        lock (listLock)
        {

            int count = tmp.Count(x => x.Username == item.Username && x.Role == item.Role);
            item.Month[month] = count;

            if (count > 2)
            {
                Debug.WriteLine($"{item.Username},{item.Role},{month}={count},{item.Month[month]}");
            }
        }
    }
    catch
    {
        //
    }
});

List<unusedrolesoccurrence>已预先填充了数据。在开始foreach之前,月数组是[0,0,0,0,0,0,0,0,0,0,0,0],int[] arr_month = new int[12];

tmp也是List<t>

什么不起作用:在循环期间,计数以及item.Month[month]的值都是正确的。但不在目标List<UnusedRolesOccurrence>中。所有Month与循环中处理的最后一个计数的值相同,例如[3,0,3,0,0,0,0,0,0,0,0,0]或[0,1,1,0,0,0,0,0,0,0,0,0 ]。而且因为并行,所以结果总是不同的。

我将int[]更改为public Dictionary<int, int> Month { get; set; }进行测试,但是行为相同。

此处的示例代码(带有//带有字典的辅助尝试,结果相同)

public class UnusedRoles
        {
            public string Username { get; set; }
            public string Role { get; set; }
            public int Month { get; set; }
        }

        public class UnusedRolesOccurrence
        {
            public string Username { get; set; }
            public string Role { get; set; }
            //public Dictionary<int, int> Month { get; set; }
            public int[] Month { get { return month; } set { month = value; } }
            public int[] month = new int[12];
        }

        public List<UnusedRoles> unusedroles = new List<UnusedRoles>();
        public List<UnusedRolesOccurrence> unusedrolesoccurrence = new List<UnusedRolesOccurrence>();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Run();
        }

        public async void Run()
        {
            unusedroles.Clear();
            unusedrolesoccurrence.Clear();

            Dictionary<int, int> dictionary_month = new Dictionary<int, int>();

            //for (int i = 0; i < 12; i++) { dictionary_month.Add(i, 0); }
            int[] arr_month = new int[12];

            unusedroles.Add(new UnusedRoles { Username = "User1", Role = "A", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User1", Role = "A", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User1", Role = "B", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User2", Role = "A", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User2", Role = "B", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User2", Role = "B", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User3", Role = "C", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User3", Role = "C", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User3", Role = "C", Month = 0 });
            unusedroles.Add(new UnusedRoles { Username = "User4", Role = "A", Month = 0 });

            var tmp = unusedroles.Select(x => new { x.Username, x.Role }).Distinct();

            foreach (var item in tmp)
            {
                unusedrolesoccurrence.Add(new UnusedRolesOccurrence
                {
                    //Username = item.Username, Role = item.Role, Month = dictionary_month
                    Username = item.Username, Role = item.Role, Month = arr_month
                });
            }

            var result = await Find(0);

            foreach (var item in unusedrolesoccurrence)
            {
                //string line = "";
                //foreach (var pair in item.Month) {
                //    line = $"{line},{pair.Value}";
                //}
                string line = $"{item.Username},{item.Role}";
                foreach (int i in item.Month)
                {
                    line = $"{line},{i}";
                }
                //Debug.WriteLine($"{item.Username},{item.Role}{line}");
                Debug.WriteLine($"{line}");

            }
        }

        public async Task<bool> Find(int month)
        {
            await Task.Run(() =>
            {
                Parallel.ForEach(unusedrolesoccurrence, (UnusedRolesOccurrence item) =>
                {
                        int count = unusedroles.Count(x => x.Username == item.Username && x.Role == item.Role &&x.Month == month);
                        item.Month[month] = count;
                        Debug.WriteLine($"{item.Username},{item.Role},count={count},item.Month[{month}]={item.Month[month]}");
                });
            });

            return true;
        }

2 个答案:

答案 0 :(得分:1)

TL; DR:您的月份数组是静态的,请不要这样做。

在您设置的并发操作期间,该类的所有所有实例共享该类UnusedRolesOccurrence的以下成员。

private static int[] month = new int[12];

删除static关键字,UnusedRolesOccurrence的每个实例将有其自己的.month数组。

注意:您在此代码中可能还有其他问题,但是您的问题来自此处的问题。

答案 1 :(得分:0)

它正在这样工作。

之前:

        int[] arr_month = new int[12];

        var tmp = unusedroles.Select(x => new { x.Username, x.Role }).Distinct();

        foreach (var item in tmp)
        {
            unusedrolesoccurrence.Add(new UnusedRolesOccurrence
            {
                //Username = item.Username, Role = item.Role, Month = dictionary_month
                Username = item.Username, Role = item.Role, Month = arr_month
            });
        }

之后:

    var tmp = unusedroles.Select(x => new { x.Username, x.Role }).Distinct();

    foreach (var item in tmp)
    {
        unusedrolesoccurrence.Add(new UnusedRolesOccurrence
        {
            //Username = item.Username, Role = item.Role, Month = dictionary_month
            Username = item.Username, Role = item.Role, Month = new int[12]
        });
    }