在下面给出的MWE(最小工作示例)中,我配置
Simulator.CpuBoundOperation("red", 150));
在线程池线程中使用红色字体旋转150次。
Simulator.CpuBoundOperation("green", 550);
使用绿色字体旋转550次。
我希望获得一个HTML输出,该输出由一串带有交替红绿数字的线程ID组成,因为它们同时运行。
不幸的是,输出显示了不需要的结果,其中所有绿色数字首先打印,然后是所有绿色数字。我试图增加迭代但它也不起作用。
如何解决此问题?
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
static class Simulator
{
private static readonly StringBuilder sb = new StringBuilder();
static Simulator()
{
string begin = "<!DOCTYPE html><html><body style='width:500px;background-color:black;font-size:20pt'><p>";
sb.Append(begin);
}
public static void CpuBoundOperation(string color, int n = 50)
{
for (long i = 0; i < n; i++)
sb.Append($"<span style='color:{color}'>{Thread.CurrentThread.ManagedThreadId} </span>");
// a white space before </span> is important
}
public static new string ToString()
{
sb.Append("</p></body></html>");
return sb.ToString();
}
}
class Test
{
static async Task Main(string[] args)
{
await Work();
File.WriteAllText("output.html", Simulator.ToString());
}
static async Task Work()
{
Task t = Task.Run(() => Simulator.CpuBoundOperation("red", 150));
Simulator.CpuBoundOperation("green", 550);
await t;
Simulator.CpuBoundOperation("blue");
}
}
答案 0 :(得分:3)
在主线程完成绿色数字之前,您的操作(显然)没有足够的时间让后台线程运行。
坦率地说,你很幸运,所有发生的事情都是后台任务在主线程等待之前没有开始。StringBuilder
不是线程安全的,所以如果你已经并发执行,你就会损坏StringBuilder
,最多会产生完全错误的输出,并导致程序崩溃最糟糕的。
不清楚为什么要将文本交错,但如果这是一个要求,则应该在单个线程中执行此操作。至少在示例程序中,还没有足够的工作来证明并发性。如果你真的想要保证并发性,你必须为主线程添加逻辑,直到后台线程才开始工作,但这有点反模式,因为它违背了主要目的。并发:最大化计算吞吐量。