C# Parallel.Foreach List<T> 中的 int[] 未正确更改
C# Parallel.Foreach int[] in List<T> not changed properly
这是我的 class:
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>
.
什么不起作用:在循环期间,count 和 item.Month[month]
的值都是正确的。但不在目标 List<UnusedRolesOccurrence>
中。所有月份都与循环中处理的最后一次计数值相同,例如[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; }
进行测试,但行为相同。
HERE EXAMPLE CODE( with // secondary try with dictionary with same result):
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;
}
TL;DR: 你的月份数组是静态的,不要这样做。
在您设置的并发操作期间,class UnusedRolesOccurrence
的以下成员被该 class 的 所有 个实例共享向上。
private static int[] month = new int[12];
删除 static 关键字,UnusedRolesOccurrence
的每个实例将拥有自己的 .month
数组。
注意:您可能在此代码中还有其他问题,但您的问题来自此处的问题。
它是这样工作的。
之前:
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]
});
}
这是我的 class:
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>
.
什么不起作用:在循环期间,count 和 item.Month[month]
的值都是正确的。但不在目标 List<UnusedRolesOccurrence>
中。所有月份都与循环中处理的最后一次计数值相同,例如[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; }
进行测试,但行为相同。
HERE EXAMPLE CODE( with // secondary try with dictionary with same result):
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;
}
TL;DR: 你的月份数组是静态的,不要这样做。
在您设置的并发操作期间,class UnusedRolesOccurrence
的以下成员被该 class 的 所有 个实例共享向上。
private static int[] month = new int[12];
删除 static 关键字,UnusedRolesOccurrence
的每个实例将拥有自己的 .month
数组。
注意:您可能在此代码中还有其他问题,但您的问题来自此处的问题。
它是这样工作的。
之前:
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]
});
}