我有10个任务列表,每个任务需要15秒。所有任务都在一个数组中,并以异步方式执行。整套不应该花费大约15秒钟吗?从下面的代码中,请注意在输出中整个集合需要21秒。当我将其更改为100个任务时,需要一分钟。它几乎就像创建任务需要一秒钟一样。我错过了什么?谢谢!
static void Main(string[] args)
{
var mainStart = DateTime.Now;
var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
tasks.Add(Task.Factory.StartNew((Object data) =>
{
var index = (int)data;
var stepStart = DateTime.Now;
Console.WriteLine("{0} Starting {1} on thread {2}...", stepStart, index, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(15000);
var stepFinish = DateTime.Now;
Console.WriteLine("{0} Finished {1} on thread {2}, duration: {3}",
stepStart, index, Thread.CurrentThread.ManagedThreadId, stepFinish - stepStart);
},
i));
}
Task.WaitAll(tasks.ToArray());
var mainFinish = DateTime.Now;
Console.WriteLine("{0} Finished, duration {1}", DateTime.Now, mainFinish - mainStart);
Console.WriteLine("Press any key to exit.");
Console.Read();
// Output
//5/25/2017 8:03:43 PM Starting 0 on thread 10...
//5/25/2017 8:03:43 PM Starting 1 on thread 11...
//5/25/2017 8:03:43 PM Starting 2 on thread 12...
//5/25/2017 8:03:43 PM Starting 3 on thread 13...
//5/25/2017 8:03:44 PM Starting 4 on thread 14...
//5/25/2017 8:03:45 PM Starting 5 on thread 15...
//5/25/2017 8:03:46 PM Starting 6 on thread 16...
//5/25/2017 8:03:47 PM Starting 7 on thread 17...
//5/25/2017 8:03:48 PM Starting 8 on thread 18...
//5/25/2017 8:03:49 PM Starting 9 on thread 19...
//5/25/2017 8:03:43 PM Finished 0 on thread 10, duration: 00:00:15.0018957
//5/25/2017 8:03:43 PM Finished 1 on thread 11, duration: 00:00:15.0175209
//5/25/2017 8:03:43 PM Finished 2 on thread 12, duration: 00:00:15.0175209
//5/25/2017 8:03:43 PM Finished 3 on thread 13, duration: 00:00:15.0165291
//5/25/2017 8:03:44 PM Finished 4 on thread 14, duration: 00:00:15.0156567
//5/25/2017 8:03:45 PM Finished 5 on thread 15, duration: 00:00:15.0156012
//5/25/2017 8:03:46 PM Finished 6 on thread 16, duration: 00:00:15.0155997
//5/25/2017 8:03:47 PM Finished 7 on thread 17, duration: 00:00:15.0155989
//5/25/2017 8:03:48 PM Finished 8 on thread 18, duration: 00:00:15.0155985
//5/25/2017 8:03:49 PM Finished 9 on thread 19, duration: 00:00:15.0156328
//5/25/2017 8:04:04 PM Finished, duration 00:00:21.0322775
//Press any key to exit.
}
答案 0 :(得分:1)
任务不是线程。如果您想保证所有这些任务同时并行运行,请尝试以下方法:
class Program
{
static void Main(string[] args)
{
var mainStart = DateTime.Now;
var threads = new List<Thread>();
for (int i = 0; i < 10; i++)
{
threads.Add(new Thread(() =>
{
var stepStart = DateTime.Now;
Console.WriteLine("{0} Starting {1} on thread {2}...", stepStart, i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(15000);
var stepFinish = DateTime.Now;
Console.WriteLine("{0} Finished {1} on thread {2}, duration: {3}",
stepStart, i, Thread.CurrentThread.ManagedThreadId, stepFinish - stepStart);
}));
}
foreach (Thread t in threads)
{
t.Start(); // Starts all the threads
}
foreach(Thread t in threads)
{
t.Join(); // Make the main thread wait for the others
}
var mainFinish = DateTime.Now;
Console.WriteLine("{0} Finished, duration {1}", DateTime.Now, mainFinish - mainStart);
Console.WriteLine("Press any key to exit.");
Console.Read();
}
}
阅读更多关于主要差异的here。
正如Jon Skeet所说:
线程是一个较低级别的概念:如果你直接启动一个线程,你知道它将是一个单独的线程,而不是在线程池等上执行。
任务不仅仅是一个抽象的&#34;在哪里运行一些代码&#34;虽然 - 它真的只是&#34;未来结果的承诺&#34;。
答案 1 :(得分:1)
名义上,异步工作允许其他事情在他们等待某事时继续......而他们这样做的方式是等待时间的东西(这通常是某种我的某种东西) / O)。为了看到这一点,你可以真正地运行工作异步时尚。例如:
static void Main( string[ ] args )
{
var totalTime = DoSomeAsyncTasks( ).GetAwaiter( ).GetResult( );
Console.WriteLine( "{0} Finished, duration {1}", DateTime.Now, totalTime );
Console.WriteLine( "Press any key to exit." );
Console.Read( );
}
async static Task<TimeSpan> DoSomeAsyncTasks( )
{
var mainStart = DateTime.Now;
var tasks = new List<Task>( );
for ( int i = 0; i < 10; i++ )
{
var id = i;
tasks.Add( DoATask( id ) );
}
await Task.WhenAll( tasks );
var mainFinish = DateTime.Now;
return mainFinish - mainStart;
}
static async Task DoATask( int stepId )
{
var stepStart = DateTime.Now;
Console.WriteLine(
"{0} Starting {1} on thread {2}...",
stepStart, stepId, Thread.CurrentThread.ManagedThreadId );
//--> more accurately model waiting for I/O...
await Task.Delay( TimeSpan.FromSeconds( 15 ) );
var stepFinish = DateTime.Now;
Console.WriteLine( "{0} Finished {1} on thread {2}, duration: {3}",
stepStart, stepId, Thread.CurrentThread.ManagedThreadId, stepFinish - stepStart );
}
...返回:
5/25/2017 11:24:36 PM Starting 0 on thread 9...
5/25/2017 11:24:36 PM Starting 1 on thread 9...
5/25/2017 11:24:36 PM Starting 2 on thread 9...
5/25/2017 11:24:36 PM Starting 3 on thread 9...
5/25/2017 11:24:36 PM Starting 4 on thread 9...
5/25/2017 11:24:36 PM Starting 5 on thread 9...
5/25/2017 11:24:36 PM Starting 6 on thread 9...
5/25/2017 11:24:36 PM Starting 7 on thread 9...
5/25/2017 11:24:36 PM Starting 8 on thread 9...
5/25/2017 11:24:36 PM Starting 9 on thread 9...
5/25/2017 11:24:36 PM Finished 9 on thread 11, duration: 00:00:15.0085175
5/25/2017 11:24:36 PM Finished 8 on thread 12, duration: 00:00:15.0085175
5/25/2017 11:24:36 PM Finished 7 on thread 13, duration: 00:00:15.0315198
5/25/2017 11:24:36 PM Finished 6 on thread 14, duration: 00:00:15.0325121
5/25/2017 11:24:36 PM Finished 5 on thread 12, duration: 00:00:15.0335121
5/25/2017 11:24:36 PM Finished 3 on thread 11, duration: 00:00:15.0335121
5/25/2017 11:24:36 PM Finished 2 on thread 12, duration: 00:00:15.0355229
5/25/2017 11:24:36 PM Finished 1 on thread 11, duration: 00:00:15.0355229
5/25/2017 11:24:36 PM Finished 4 on thread 14, duration: 00:00:15.0335121
5/25/2017 11:24:36 PM Finished 0 on thread 13, duration: 00:00:15.0545213
5/25/2017 11:24:51 PM Finished, duration 00:00:15.0665191
(我做了所有相同的代码 - 并且接受的答案确实......只是将它扩展到方法中以使其更具说明性。)
您应该从中看到的是,每项任务大约在同一时间开始,每项任务大约需要15秒,但总运行时间也大约为15秒。这是因为,当任务正在等待时,它会让其他工作运行。还要注意,一切都在同一个单线程上运行。这项工作是等待的。它非常酷 - 可能更像你可能期待的那样。
答案 2 :(得分:1)
我错过了什么?
线程池的工作原理。
您可以将线程池视为线程集合,以及要完成的工作队列。通常,线程池的线程集合与CPU核心数大致相同 - 因为一次只有那么多线程可以实际执行(即运行代码)。
此外,当线程池比线程有更多工作要做时,它会向其线程集合添加更多线程。但它限制了线程注入速率 - IIRC,当前线程注入速率就像每2秒一个新线程。这种限制对于防止螺纹颠簸是必要的;创建和销毁线程的成本很高,因此线程池使用注入速率限制作为启发式。
所以,one answer这里通过使用普通线程来避免线程池(在现实世界的代码中我永远不推荐)。 Another answer通过使用异步任务来避免线程池。这个答案只是解释了为什么你看到了这种行为。
但是如果你想同时(和同步) on 线程池运行它们,你可以通过告诉线程池到increase its minimum number of threads来做到这一点。
答案 3 :(得分:0)
Factory.StartNew只是在TaskScheduler上排队任务 - 如果所有线程都忙于其他工作,它就不会立即运行任务。如果您记录开始时间,那么您将看到其中至少有一项任务没有启动6秒。