c# - C# 使基本多线程循环返回正确的值
问题描述
首先,我是 C# 新手,这是我编写的第一个使用线程的程序。对不起,如果它有点基本。
这是我的应用程序:
class Program
{
static void AddNumbers()
{
int count = 0;
for (int counter = 0; counter < 90000000; counter++)
{
count += counter;
}
}
static void Main()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 50; i++)
{
// Non-threaded
//AddNumbers();
//Console.WriteLine((i + 1).ToString());
// Threaded
new Thread(() =>
{
//Thread.CurrentThread.IsBackground = true;
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((i + 1).ToString());
}).Start();
}
stopwatch.Stop();
Console.WriteLine("Time elapsed: {0:hh\\:mm\\:ss}", stopwatch.Elapsed);
Console.ReadLine();
}
}
它只是循环i
时间并每次添加一堆数字。当我运行AddNumbers()
非多线程版本时,它会正确显示1, 2, 3...
等,但是当我多线程运行它时,它会返回 2-3 次相同的索引,跳过一些,并在所有线程执行之前返回秒表值。
有人可以帮助找出我的错误在哪里,最重要的是澄清我对线程如何在 C# 中工作的想法?谢谢!
解决方案
当我运行非多线程的 AddNumbers() 版本时,它正确显示 1、2、3... 等,但是当我多线程运行它时,它返回相同的索引 2-3 次,跳过一些
它发生了,因为i
被捕获,但在外部循环中发生了变化。
在此处阅读更多信息:
在 C# http://www.trycatchthat.com/csharp/fundamentals/2016/02/29/csharp-closure-loops.html的循环中捕获的变量
为了使其正常工作,您需要保存本地副本:
for (int i = 0; i < 50; i++)
{
// Non-threaded
//AddNumbers();
//Console.WriteLine((i + 1).ToString());
// Threaded
int iCopy = i;
new Thread(() =>
{
//Thread.CurrentThread.IsBackground = true;
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((iCopy + 1).ToString());
}).Start();
}
在所有线程执行之前返回秒表值
它发生了,因为你实际上从来没有加入你的线程并等待它们执行。
它可以通过存储所有线程并调用来实现thread.Join()
:
Thread[] threads = new Thread[50];
for (int i = 0; i < 50; i++)
{
// Non-threaded
//AddNumbers();
//Console.WriteLine((i + 1).ToString());
// Threaded
int iCopy = i;
threads[i] = new Thread(() =>
{
//Thread.CurrentThread.IsBackground = true;
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((iCopy + 1).ToString());
});
thread[i].Start();
}
for (int i = 0; i < 50; i++)
threads[i].Join();
在此处阅读有关等待线程完成的更多信息:
在 TPL 发明之前,人们就是这样做的。
现在,一般规则不是使用Thread
,而是使用Task
orParallel
代替。
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task[] tasks = new Task[50];
for (int i = 0; i < 50; i++)
{
int iCopy = i;
tasks[i] = Task.Run(() => {
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((iCopy + 1).ToString());
});
}
Task.WaitAll(tasks);
推荐阅读
- javascript - React Native 如何在数据中设置状态数据?
- css - 是否可以根据不断变化的类为 ::after 设置动画?
- ios - 如何选择系统键盘作为文本字段的唯一输入键盘类型?
- android - 如何在 RxJava2 中合并多个请求?
- java - Android Spinner 用对象填充
- sql - SQL 插入在 DGlux 应用程序中不起作用
- php - 解析错误:语法错误,意外的 'const' (T_CONST),期望 Laravel 项目中的变量 (T_VARIABLE)
- julia - 我如何在 Julia 中按价值发货?
- sql - 如何从表中选择不同的值?
- c# - 编组指向数组 P/Invoke 的指针