基本上我一直在使用多线程,但它一直没有按照应有的方式工作。我立即尝试在标题中描述问题,以便在线找到答案,但没有发现任何关系。
这是我开发的一个应用程序,用于更好地理解多任务处理,以便在实际应用程序中有效使用。
基本上它的作用是你在文本框中写一些内容并选择你想要的线程数,它会在底部附加日志框。因此,它将显示每个线程运行了多少次 BUT 问题是它仍然会在后台冻结UI。
这里是它在3个线程上给出的输出(它可以处理少量(少于10个)线程):
这是完整的代码 -
public partial class thread : Form
{
Thread[] threads;
int amountOf;
bool stop = false;
int threadAmt = 0;
public thread()
{
InitializeComponent();
}
delegate void SetTextCallback(string text);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
amountOf = (int)amtThreads.Value;
threads = new Thread[amountOf];
//Define threads
for (int i = 0; i < amountOf; i++)
{
threads[i] = new Thread(new ThreadStart(job));
}
//Start threads
foreach (Thread t in threads)
{
t.IsBackground = true;
t.Start();
}
}
private void logIt(string text)
{
if (outputResult.InvokeRequired)
{
SetTextCallback cb = new SetTextCallback(logIt);
Invoke(cb, new object[] { text });
}
else
outputResult.AppendText(text);
}
private void job()
{
int threadNum = threadAmt++;
int howMany = 0;
do
{
howMany++;
logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
Thread.Sleep(1);
}
while (!stop);
}
private void Start_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
Start.Enabled = false;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
MessageBox.Show("Error: " + e.Error.Message);
else if (e.Cancelled)
MessageBox.Show("Application canceled.");
}
private void Stop_Click(object sender, EventArgs e)
{
stop = true;
backgroundWorker1.CancelAsync();
Stop.Enabled = false;
}
private void Clear_Click(object sender, EventArgs e)
{
outputResult.Clear();
}
}
在放入10个或更多线程后,UI继续冻结。 我想知道的另一件事是暂停和恢复线程。当您停止线程循环然后重新启用它时,它只会显示一个结果。它不会继续循环。
答案 0 :(得分:2)
你的问题不是创建过多的线程而是你的线程正在过度更新UI 。
你的job
方法有一个非常紧凑的循环,你调用logIt
然后睡眠一毫秒然后重复这个过程。日志编组调用UI线程调用outputResult.AppendText(text);
。这种编组工作发生在消息泵上。
您实际上已经溢出了消息泵,基本上更新了TextBox
,因此UI无法响应而无法处理任何其他内容。
将10个线程的数据相乘,所有日志记录之间的记录都很小,并且您的用户界面将会冻结。
考虑将Thread.Sleep
增加至Thread.Sleep(500)
1/2秒。
更改此代码:
private void job()
{
int threadNum = threadAmt++;
int howMany = 0;
do
{
howMany++;
logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
Thread.Sleep(1); // Oww!! Should this have been 1000 instead of 1. 1000 is 1 second.
}
while (!stop);
}
...为:
private void job()
{
int threadNum = threadAmt++;
int howMany = 0;
do
{
howMany++;
logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
Thread.Sleep(500); // e.g. 1/2 second
}
while (!stop);
}
你对线程很感兴趣。自从引入Thread
以来,.NET使线程化变得更加容易,特别是当线程需要操作UI时。现在通常最好不要显式创建线程,而是使用备用API。
您可能希望通过async
和await
关键字查看.NET 异步方法,因为它们在您的情况下可能非常有用。
另一个时间的主题