Thread.Sleep会妨碍其他线程吗?

dem*_*xSH 9 c# multithreading parallel-for thread-sleep

这是一个控制台程序,希望10个线程批量启动,等待5秒,然后批量停止.

static void Main(string[] args)
{
    System.Threading.Tasks.Parallel.For(0, 10, (index) =>
    {
        Action<int> act = (i) =>
        {
            Console.Write("start {0} ", i);
            Thread.Sleep(5000);
        };

        act.BeginInvoke(index, OnTaskComplete, index);
    });

    Console.ReadKey();
}

static void OnTaskComplete(IAsyncResult res)
{
    Console.Write("finish {0} ", res.AsyncState);
}
Run Code Online (Sandbox Code Playgroud)

但结果不是我的预期,10个线程一个接一个地慢慢开始(大约1秒间隔),甚至一些"完成"在一些"开始"之前出现.

当注释掉Thread.Sleep时,所有线程都在flash中开始和结束.

Thread.Sleep影响其他线程吗?无论如何要做一个纯粹的空闲时间?

/ - - - - - - - - - - - - - - -编辑 - - - - - - - - - - ----------

同样的问题也发生在:

static void Main(string[] args)
{
    System.Threading.Tasks.Parallel.For(0, 10, (index) =>
    {
        Console.Write("start {0} ", index);
        Thread.Sleep(5000);
        Console.Write("fnish {0} ", index);
    });

    Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)

- - - - - - - - - - - 编辑 - - - - - - - - - - - -

最后我找到了一种替代thread.sleep的可爱方法

static void Main(string[] args)
{
    System.Threading.Tasks.Parallel.For(0, 10, (index) =>
    {
        Console.Write("start {0} ", index);

        var t1 = new System.Threading.Timer(new TimerCallback(MyTimerCallback), index, 5000, 0); 
    });

    Console.ReadKey();
}

static void MyTimerCallback(object o)
{
    Console.Write("Timer callbacked ");
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 13

这是设计的.您正在看到线程池管理器尝试将有限数量的线程保持在执行状态.重要的是确保您的程序没有运行比您的机器具有cpu内核更多的线程.当Windows被迫开始在活动线程之间交换核心时,效率低下,工作量减少.线程池管理器不够聪明,不知道线程正在休眠而实际上没有执行任何工作.

在双核机器上,您将看到前两个线程立即开始.然后,当线程管理器注意到活动线程没有取得任何进展并且可能被阻塞时,允许其他线程一个接一个地运行,间隔为1秒.释放线程并执行Console.Write()调用的顺序不确定.

这当然是一个人工测试,真正的线程不会睡觉.如果你有长时间阻塞的线程,等待I/O请求完成,例如然后使用线程池线程(任务)不是最好的解决方案.


Ale*_*Aza 5

TaskCreationOptions.LongRunning将'删除'ThreadPool限制.
我不知道这个简单的方法来指定TaskCreationOptions.LongRunningParallel.For.
但是,您可以使用Task类实现相同的效果:

Action<int> action = i =>
    {
        Console.Write("start {0} ", i);
        Thread.Sleep(5000);
        Console.Write("finish {0} ", i);
    };

var tasks = Enumerable.Range(0, 100)
    .Select(arg => Task.Factory.StartNew(() => action(arg), TaskCreationOptions.LongRunning))
    .ToArray();

Task.WaitAll(tasks);
Run Code Online (Sandbox Code Playgroud)

如果没有TaskCreationOptions.LongRunning它,它将以与您完全相同的方式运行Parallel.For.