我有一个测试客户端,我可以在其中指定要创建的线程数。我根据用户选择的数字运行for循环并启动我的线程。我将线程存储在List中,以便我可以在稍后阶段监视/终止线程。当我运行循环时,我可以看到所有线程都有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个客户”这一行的下方。每个阅读1000键&#39;每次迭代0,1,2 ...每3秒有3个条目。我期待5个线程正在运行。
根据@jackncoke,我确实尝试使用它而不是for循环:
Parallel.For(0, _numClients, i => RunNamedPipeServerTest(i));
由于某种原因,它只创建一个线程。
然后我也试过了:
Parallel.For(0, _numClients, i => RunNamedPipeThread(i));
这可行,但它仍然无法创建正确数量的线程。另外,如果您查看方法 RunNamedPipeThread ,我仍然明确地为 RunNamedPipeServerTest 创建线程。
答案 0 :(得分:1)
考虑使用Parallel.For而不是创建大量自己的线程。它负责您的任务和线程调度,您可以通过指定ParallelOptions来指定要使用的最大线程数,以防止操作占用系统的所有资源。
最重要的是确保您使用Concurrent Collection。这些集合针对您的场景进行了优化,并允许您(大多数情况下)不担心锁争用,死锁和过多的其他潜在危险。
由于某种原因,它只创建一个线程。
虽然Parallel.For
和Parallel.ForEach
可能会安排多个线程,但并不一定意味着它总是如此,正如文档所述:
执行for(For in Visual Basic)循环,其中迭代可以并行运行。
一般来说,如果使用并发集合并且工作负载可以兼容,则运行时将决定在其上抛出多个线程。