在C#中的for循环中创建多个线程
本文关键字:创建 线程 循环 中的 for | 更新日期: 2023-09-27 17:59:21
我有一个测试客户端,可以在其中指定要创建的线程数。我根据用户选择的数字运行for循环并启动线程。我将线程存储在列表中,以便在稍后阶段监视/终止线程。当我运行循环时,我可以看到所有线程都有ThreadState.Running。然而,我总是看到创建的线程更少。请帮助
private void btnReadMTNPServer_Click(object sender, EventArgs e)
{
DisableTestButtons();
SetValuesFromControls();
ResetThreads();
_metrics.Clear();
_runTest = true;
_keys = GetTestKeysList();
for (var i = 0; i < _numClients; i++)
{
var index = i;
TestThreads.Add(RunNamedPipeThread(index));
AppendConsoleText(string.Format("ThreadState: {0}", TestThreads[index].ThreadState));
Thread.Sleep(50);
}
AppendConsoleText(string.Format("Starting {0} Clients. Each Reading {1} Keys", TestThreads.Count, nudTestReadKeyCount.Value));
}
private Thread RunNamedPipeThread(int i)
{
var thread = new Thread(RunNamedPipeServerTest)
{
Name = i.ToString("D3")
//IsBackground = true
};
while (thread.ThreadState != ThreadState.Running)
thread.Start(i);
return thread;
}
private void RunNamedPipeServerTest(object i)
{
var id = (int)i;
var iteration = 0;
var list = new List<short>();
var client = new PipeClient("DHM");
{
client.Start();
while (_runTest)
{
var startTimeStamp = DateTime.Now;
foreach (var key in _keys.TakeWhile(key => _runTest))
{
list.Add(client.GetValue(key));
if (_delayPerKey > 0)
Thread.Sleep(_delayPerKey);
}
var finishTimeStamp = DateTime.Now;
//Keep the client connected using KeepAlive.
client.KeepAlive();
_metrics.Add(new PerformanceMetric(id.ToString("D3"), startTimeStamp, finishTimeStamp));
AppendConsoleText(string.Format("{3}:{0}:Start:{1}, Took {2} ms", id.ToString("D3"), startTimeStamp.ToString("mm:ss.ffff"), finishTimeStamp.Subtract(startTimeStamp).TotalMilliseconds, iteration++));
//Wait before sending request for data.
Thread.Sleep(_testFrequency);
}
client.Stop();
}
if (cbxDisplayValues.Checked)
AppendConsoleText(string.Format("{0}", string.Join(",", list)));
}
private void ResetThreads()
{
if (TestThreads == null)
TestThreads = new List<Thread>();
_runTest = false;
TestThreads.ForEach(t => t.Abort());
TestThreads.Clear();
}
private void AppendConsoleText(string text)
{
if (txtConsole.InvokeRequired)
{
Invoke(new MethodInvoker(() => txtConsole.AppendText(string.Format("{0}{1}", text, Environment.NewLine))));
}
else
{
txtConsole.AppendText(string.Format("{0}{1}", text, Environment.NewLine));
}
}
这是我经常在文本框中看到的结果。有5个线程正在运行,但只有3个线程正在写入。不过,这种情况是随机发生的。有时5个人按预期写,有时他们没有。
ThreadState: Running
ThreadState: Running
ThreadState: Running
ThreadState: Running
ThreadState: Running
Starting 5 Clients. Each Reading 1000 Keys
0:002:Start:53:55.5393, Took 187.4653 ms
0:003:Start:53:55.6331, Took 125.0191 ms
0:004:Start:53:55.7424, Took 109.4014 ms
1:002:Start:53:58.7539, Took 62.4642 ms
1:003:Start:53:58.7851, Took 62.5031 ms
1:004:Start:53:58.8789, Took 46.8898 ms
2:002:Start:54:01.8316, Took 62.4693 ms
2:003:Start:54:01.8629, Took 125.0298 ms
2:004:Start:54:01.9410, Took 93.7239 ms
3:002:Start:54:04.9149, Took 52.3515 ms
3:003:Start:54:04.9985, Took 62.5211 ms
3:004:Start:54:05.0454, Took 46.8765 ms
4:002:Start:54:07.9954, Took 46.77 ms
4:003:Start:54:08.0736, Took 46.7811 ms
4:004:Start:54:08.1203, Took 46.8748 ms
5:002:Start:54:11.0636, Took 46.7713 ms
5:003:Start:54:11.1417, Took 62.4283 ms
5:004:Start:54:11.1885, Took 46.8748 ms
6:002:Start:54:14.1308, Took 39.5712 ms
6:003:Start:54:14.2173, Took 54.1113 ms
6:004:Start:54:14.2486, Took 47.9687 ms
7:002:Start:54:17.1964, Took 51.7147 ms
7:003:Start:54:17.2795, Took 62.3954 ms
7:004:Start:54:17.3107, Took 46.8722 ms
8:002:Start:54:20.2644, Took 46.77 ms
8:003:Start:54:20.3581, Took 46.77 ms
8:004:Start:54:20.3738, Took 46.7721 ms
9:002:Start:54:23.3386, Took 46.77 ms
9:003:Start:54:23.4324, Took 46.7704 ms
9:004:Start:54:23.4480, Took 46.7969 ms
编辑#1:发生的情况是,有5个线程表示它们正在运行。然而,如果你仔细看下面写着"启动5个客户"的行。每个Reading 1000 Keys’每个迭代0、1、2…每三秒有3个条目。我预计5个线程正在运行。
根据@jackncoke,我确实尝试过使用这个而不是for循环:
Parallel.For(0, _numClients, i => RunNamedPipeServerTest(i));
出于某种原因,它只创建了一个线程。
然后我也尝试了:
Parallel.For(0, _numClients, i => RunNamedPipeThread(i));
这是可行的,但是它仍然没有创建正确数量的线程。此外,如果您查看方法RunNamedPipeThread,我仍然显式地为RunNamedPipeServerTest创建线程。
考虑使用Parallel.For,而不是创建大量自己的线程。它为您处理任务和线程调度,您可以通过指定ParallelOptions来指定要使用的最大线程数量,以防止操作占用系统的所有资源。
除此之外,请确保您使用的是并发集合。这些集合针对您的场景进行了优化,并允许您(在大多数情况下)不必担心锁争用、死锁和大量其他潜在危险。
出于某种原因,它只创建了一个线程。
虽然Parallel.For
和Parallel.ForEach
可能调度多个线程,但这并不一定意味着它总是会,正如文档所述:
执行for(Visual Basic中的for)循环,其中的迭代可以并行运行。
一般来说,如果您使用并发集合,并且工作负载是可并行的,则运行时将决定向其抛出多个线程。