The code below is simplified. There is a massive method which iterates many times. The threaded method receives an element of a List<Class>
.
Because the threaded method modifies an element which is an object in the method, I do not want that the same argument is loaded on the separate threads concurrently. Because each element is independent, I want that the method with each one runs concurrently.
How to run the method with the same argument sequentially and run the method with a different argument concurrently?
Do I have to verify each running thread one by one before New & Start the method, whether there is the method with the same argument or not?
class Class1
{
// something
}
private void Form1_Load(object sender, EventArgs e)
{
List<Class1> _List = new();
for (int i = 0; i < 10; i )
{
_List.Add(new Class1 { });
}
for (int i = 0; i < 10; i )
{
Thread _Thread = new(Method1);
_Thread.Start(_List[new Random().Next(10)]); // the argument can be consecutively same element of List1
}
}
void Method1(object _Object)
{
// modifies _Object
}
CodePudding user response:
If a random order is really required, randomize the list before using it: Randomize a List<T>
Creating new threads is expensive, prefer ThreadPool
To process a list of items in parallel, use
Parallel.ForEach(_List, Method1)
CodePudding user response:
You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive
and add using System.Reactive.Linq;
- then you can do this:
void Main()
{
var foos = new [] { new Foo("A"), new Foo("B"), new Foo("C"), new Foo("D") };
var query =
from n in Observable.Range(0, 1000).Select(n => __random.Next(foos.Length))
group foos[n] by foos[n].Name into grouped_foos
from gf in grouped_foos.ObserveOn(Scheduler.Default)
select new { Foo = gf, ManagedThreadId = Method1(gf) };
query
.ToArray()
.Select(x => x.GroupBy(y => (y.Foo, y.ManagedThreadId)).Select(y => (y.Key.Foo, y.Key.ManagedThreadId, Count: y.Count())))
.Subscribe(xs =>
Console.WriteLine(
String.Join(
Environment.NewLine,
xs.Select(x => $"{x.Count} x {x.Foo.Name} {x.Foo.Counter} run on thread {x.ManagedThreadId}"))));
}
int Method1(Foo foo)
{
foo.Counter = foo.Counter 1;
return System.Threading.Thread.CurrentThread.ManagedThreadId;
}
private static Random __random = new Random();
public class Foo
{
public int Counter { get; set; } = 0;
public string Name { init; get; }
public Foo(string name)
{
this.Name = name;
}
public override int GetHashCode() => this.Name.GetHashCode();
public override bool Equals(object obj) => obj is Foo f ? this.Name.Equals(f.Name) : false;
}
When I run that I get this typical output:
259 x A 259 run on thread 38
239 x D 239 run on thread 14
238 x C 238 run on thread 11
264 x B 264 run on thread 36
The code is creating a sequence of 1_000 indices randomly selecting a Foo
from 4 distinct instances. It then groups by those instances and performs some processing. The processing returns the managed thread id to see which thread ran which code.