15、从线程返回结果
从线程返回结果
知识点概述
在多线程编程中,经常需要从工作线程获取计算结果。.NET提供了多种方式来实现从线程返回结果:
- Thread + 共享变量: 通过共享变量或字段存储结果
- Thread + 回调委托: 使用委托回调传递结果
- Task
: 返回强类型结果的任务(推荐) - BackgroundWorker: 提供进度报告和结果返回
- ThreadPool.QueueUserWorkItem: 配合ManualResetEvent返回结果
代码案例
案例1:使用共享变量返回结果
using System;
using System.Threading;
class SharedVariableResult
{
private static int _result;
private static bool _completed = false;
static void Main()
{
Thread workerThread = new Thread(CalculateSum);
workerThread.Start();
// 等待计算完成
while (!_completed)
{
Console.WriteLine("等待计算结果...");
Thread.Sleep(100);
}
Console.WriteLine($"计算结果: {_result}");
}
static void CalculateSum()
{
Console.WriteLine("开始计算1到1000的和...");
int sum = 0;
for (int i = 1; i <= 1000; i++)
{
sum += i;
if (i % 100 == 0) // 模拟较长的计算过程
{
Thread.Sleep(50);
}
}
_result = sum;
_completed = true;
Console.WriteLine("计算完成");
}
}
案例2:使用回调委托返回结果
using System;
using System.Threading;
class CallbackResult
{
static void Main()
{
Console.WriteLine("启动异步计算...");
// 传递回调委托
Thread workerThread = new Thread(() => CalculateFactorial(10, OnCalculationComplete));
workerThread.Start();
workerThread.Join();
Console.WriteLine("主线程继续执行其他任务...");
Thread.Sleep(1000);
Console.WriteLine("程序结束");
}
static void CalculateFactorial(int number, Action<long> callback)
{
Console.WriteLine($"开始计算 {number} 的阶乘...");
long result = 1;
for (int i = 1; i <= number; i++)
{
result *= i;
Thread.Sleep(100); // 模拟计算延迟
}
// 通过回调返回结果
callback(result);
}
static void OnCalculationComplete(long result)
{
Console.WriteLine($"计算完成,结果: {result}");
}
}
案例3:使用Task返回结果(推荐方式)
using System;
using System.Threading.Tasks;
class TaskResult
{
static async Task Main()
{
Console.WriteLine("启动多个异步计算任务...");
// 启动多个返回结果的任务
Task<int> sumTask = CalculateSumAsync(1, 100);
Task<double> averageTask = CalculateAverageAsync(new[] { 1.5, 2.3, 3.7, 4.1, 5.9 });
Task<string> processTask = ProcessDataAsync("Hello World");
// 等待所有任务完成并获取结果
int sum = await sumTask;
double average = await averageTask;
string processed = await processTask;
Console.WriteLine($"求和结果: {sum}");
Console.WriteLine($"平均值: {average:F2}");
Console.WriteLine($"处理结果: {processed}");
}
static Task<int> CalculateSumAsync(int start, int end)
{
return Task.Run(() =>
{
Console.WriteLine($"计算 {start} 到 {end} 的和...");
int sum = 0;
for (int i = start; i <= end; i++)
{
sum += i;
}
Console.WriteLine("求和计算完成");
return sum;
});
}
static Task<double> CalculateAverageAsync(double[] numbers)
{
return Task.Run(() =>
{
Console.WriteLine("计算数组平均值...");
double sum = 0;
foreach (double num in numbers)
{
sum += num;
}
Console.WriteLine("平均值计算完成");
return sum / numbers.Length;
});
}
static Task<string> ProcessDataAsync(string input)
{
return Task.Run(() =>
{
Console.WriteLine("处理字符串数据...");
// 模拟数据处理
string result = input.ToUpper().Replace(" ", "_");
Console.WriteLine("字符串处理完成");
return result;
});
}
}
案例4:使用ManualResetEvent同步结果
using System;
using System.Threading;
class ManualResetEventResult
{
private static int _result;
private static ManualResetEvent _resetEvent = new ManualResetEvent(false);
static void Main()
{
Console.WriteLine("启动后台计算...");
ThreadPool.QueueUserWorkItem(PerformCalculation);
Console.WriteLine("主线程执行其他任务...");
// 模拟主线程的其他工作
for (int i = 0; i < 3; i++)
{
Console.WriteLine($"主线程任务 {i + 1}");
Thread.Sleep(500);
}
Console.WriteLine("等待计算结果...");
_resetEvent.WaitOne(); // 等待计算完成
Console.WriteLine($"最终结果: {_result}");
}
static void PerformCalculation(object state)
{
Console.WriteLine("后台线程开始计算...");
// 模拟复杂计算
int result = 0;
for (int i = 1; i <= 50; i++)
{
result += i * i;
Thread.Sleep(50); // 模拟计算时间
}
_result = result;
Console.WriteLine("后台计算完成");
// 通知主线程计算完成
_resetEvent.Set();
}
}
案例5:复杂场景:多个线程协作返回结果
using System;
using System.Threading;
using System.Collections.Concurrent;
class MultiThreadCooperation
{
private static ConcurrentQueue<int> _results = new ConcurrentQueue<int>();
private static CountdownEvent _countdown = new CountdownEvent(3);
static void Main()
{
Console.WriteLine("启动多线程协作计算...");
// 启动多个工作线程
for (int i = 0; i < 3; i++)
{
int workerId = i + 1;
Thread worker = new Thread(() => WorkerTask(workerId));
worker.Name = $"Worker-{workerId}";
worker.Start();
}
// 等待所有工作线程完成
_countdown.Wait();
// 收集并处理所有结果
Console.WriteLine("\n所有工作线程完成,收集结果:");
int totalResult = 0;
while (_results.TryDequeue(out int result))
{
Console.WriteLine($"获取到结果: {result}");
totalResult += result;
}
Console.WriteLine($"最终汇总结果: {totalResult}");
}
static void WorkerTask(int workerId)
{
Console.WriteLine($"{Thread.CurrentThread.Name} 开始工作");
// 每个工作线程计算不同的值
int result = workerId * workerId * 10;
// 模拟工作时间
Thread.Sleep(1000 + workerId * 300);
// 将结果添加到队列
_results.Enqueue(result);
Console.WriteLine($"{Thread.CurrentThread.Name} 完成,结果: {result}");
// 通知完成
_countdown.Signal();
}
}
知识点总结
- 共享变量方式: 简单直接,但需要注意线程安全和同步问题
- 回调委托: 提供了更好的封装,支持异步通知机制
- Task
: 现代推荐方式,类型安全,支持异步/等待模式 - 同步原语: ManualResetEvent、CountdownEvent等用于线程间同步
- 并发集合: ConcurrentQueue等提供线程安全的数据交换
- 错误处理: 需要考虑线程执行中的异常处理和结果验证
- 性能考虑: 选择合适的方式平衡代码复杂度和执行效率

浙公网安备 33010602011771号