在下面给出的 MWE(最小工作示例)中,我配置了
Simulator.CpuBoundOperation("red", 150));
在线程池线程中以红色字体旋转 150 次。Simulator.CpuBoundOperation("green", 550);
以绿色字体旋转 550 次。
我想要获得一个 HTML 输出,其中包含一串线程 id 和交替的红绿数字,因为它们是同时运行的。
不幸的是,输出显示了不需要的结果,其中首先打印所有绿色数字,然后打印所有红色数字。我尝试增加迭代次数,但效果不佳。
如何解决这个问题?
MWE
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");
}
}
最佳答案
在主线程完成绿色数字之前,您的操作(显然)没有花费足够的时间来运行后台线程。
坦率地说,你很幸运,所发生的只是后台任务直到主线程等待才开始。 StringBuilder
不是线程安全的,因此如果您并发执行,您就会损坏 StringBuilder
,充其量会产生完全错误的输出,最坏的情况下会导致程序崩溃。
尚不清楚为什么要交错文本,但如果这是必需的,则应该在单个线程中执行此操作。无论如何,没有足够的工作来证明并发性的合理性,至少在示例程序中是这样。如果您确实想保证并发性,则必须为主线程添加逻辑,以便在后台线程开始工作之前不会开始工作,但这有点反模式,因为它违背了并发性的主要目的:最大化吞吐量计算。
关于c# - 如何同时构建字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46987121/