我一直试图确定与我的其余代码同时/并行运行代码的最佳方式,可能是使用了一个线程。根据我的阅读,在现代C#中使用Thread
类型是禁忌。最初我认为Parallel.Invoke()
,但结果是阻止调用,直到所有内部工作完成。
在我的应用程序中,我不需要等待任何事情来完成,我不关心获得结果,我需要完全独立于当前线程的代码。基本上是"火灾和忘记"想法。
根据我的理解,Task.Factory.StartNew()
是与当前运行的代码同时/并行运行一段代码的正确方法。
基于此,我认为下面的代码会随机打印出来" ABABBABABAA"。
void Main()
{
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10; i++)
{
Console.Write("A");
}
});
for (int i = 0; i < 10; i++)
{
Console.Write("B");
}
}
然而,它:
for
交换,反之亦然,打印出相同的序列,这看起来很奇怪。因此,这让我认为Task.Factory.StartNew()
实际上从未将工作安排到另一个线程,几乎就像调用StartNew
是阻塞调用一样。
鉴于要求我不需要获得任何结果或等待/ await
,我是否更容易创建新的Thread
并在那里运行我的代码?我遇到的唯一问题是使用Thread
似乎与现代最佳实践和#34; C#6.0中的并发和#34;规定:
一旦你键入新的Thread(),它就结束了;您的项目已有遗留代码
答案 0 :(得分:4)
实际上,Task.Factory.StartNew确实在一个单独的线程上运行,每次失去竞争的唯一原因是因为任务创建时间。这是证明它的代码
static void Main(string[] args)
{
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10; i++)
{
Console.Write("A");
Thread.Sleep(1);
}
});
for (int i = 0; i < 10; i++)
{
Console.Write("B");
Thread.Sleep(1);
}
Console.ReadKey();
}
答案 1 :(得分:1)
你确定吗? “即发即忘”的确意味着&#34;我完全可以忽略异常。&#34;由于这不是大多数人想要的,因此一种常见的方法是对工作进行排队并保存表示该工作的在我的应用程序中,我不需要等待任何事情来完成,我不关心获得结果,我需要完全独立于当前线程的代码。基本上是&#34;火灾和忘记&#34;想法。
Task
,并在&#34; end&#34;无论你的程序做了什么,只是为了确保不完全不能完成的工作确实成功完成。
我一直试图确定与我的其余代码同时/并行运行代码的最佳方式,可能是使用了一个线程。从我所读过的内容来看,在现代C#中使用Thread类型是禁忌。最初我认为是Parallel.Invoke(),但结果是阻塞调用,直到所有内部工作完成。
是的,并行代码将阻塞调用线程。这可以通过将并行调用包装在Task.Run
中来避免(在我的书中的食谱7.4中说明)。
在您的特定情况下(例如,在即发即弃的情况下),您可以放弃await
并且只有Task.Run
。虽然如上所述,将Task
隐藏在某个地方并await
以后可能会更好。
根据我的理解,Task.Factory.StartNew()是与当前运行的代码同时/并行运行一段代码的正确方法。
不,StartNew
is dangerous并且只应作为最后的手段使用。正确的技术是Task.Run
,如果你有真正的并行工作(即很多块的CPU绑定代码),那么Task.Run
包装Parallel
/ PLINQ最好。
基于此,我认为下面的代码会随机打印出来&#34; ABABBABABAA&#34;。
作为others have noted,这只是竞争条件。将工作排队到线程池需要花费时间,计算机可以非常快地计算到10。 (写入输出要慢很多,但这里仍然太快)。 Task.Run
(或手动Thread
)会出现同样的问题。