C# 睡眠会妨碍其他线程吗?

C# 睡眠会妨碍其他线程吗?,c#,multithreading,thread-sleep,parallel-for,C#,Multithreading,Thread Sleep,Parallel For,这是一个控制台程序,需要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.

这是一个控制台程序,需要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);
}
-----------编辑------------

最后我找到了一个很好的方法来代替睡眠

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 ");
}

这是故意的。您会看到线程池管理器试图将有限数量的线程保持在执行状态。确保程序运行的线程数不超过机器的cpu核心数,这一点很重要。这是低效的,当Windows被迫开始在活动线程之间交换内核时,完成的工作更少。线程池管理器不够聪明,无法知道线程正在休眠,实际上没有执行任何工作

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


这是一个人工测试,当然,真正的线程不会休眠。如果线程阻塞很长时间,等待I/O请求完成,例如,使用线程池线程任务并不是最佳解决方案。

在写入控制台时,我稍微更新了代码以显示线程ID:

Console.WriteLine("start index:{0} thread id:{1} Time:{2} ", index, Thread.CurrentThread.ManagedThreadId.ToString(), DateTime.Now.ToLongTimeString());
Thread.Sleep(5000);
ConsoleWriteLine("finish index:{0} thread id:{1} Time:{2} ", index, Thread.CurrentThread.ManagedThreadId.ToString(), DateTime.Now.ToLongTimeString());
我的机器是双核的,这是我得到的输出。这会让你对正在发生的事情有一种感觉。请记住,循环可能并不总是按顺序运行,即0到9,如果是并行的,它会获取数组的一块并通过lambda运行每个项

输出:

start  index:1 thread id:11 Time:11:07:17 PM
start  index:0 thread id:9  Time:11:07:17 PM
start  index:5 thread id:10 Time:11:07:17 PM
start  index:6 thread id:12 Time:11:07:18 PM
start  index:2 thread id:13 Time:11:07:19 PM
start  index:7 thread id:14 Time:11:07:20 PM
start  index:3 thread id:15 Time:11:07:21 PM
start  index:8 thread id:16 Time:11:07:22 PM
finish index:0 thread id:9  Time:11:07:22 PM
start  index:4 thread id:9  Time:11:07:22 PM
finish index:1 thread id:11 Time:11:07:22 PM
start  index:9 thread id:11 Time:11:07:22 PM
finish index:5 thread id:10 Time:11:07:22 PM
finish index:6 thread id:12 Time:11:07:23 PM
finish index:2 thread id:13 Time:11:07:24 PM
finish index:7 thread id:14 Time:11:07:25 PM
finish index:3 thread id:15 Time:11:07:26 PM
finish index:8 thread id:16 Time:11:07:27 PM
finish index:4 thread id:9  Time:11:07:27 PM
finish index:9 thread id:11 Time:11:07:27 PM
TaskCreationOptions.LongRunning将“删除”线程池限制。 我不知道指定TaskCreationOptions.LongRunning for Parallel.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);

如果没有TaskCreationOptions.LongRunning,它将以与并行程序完全相同的方式运行。对于did。

您可以定义纯空闲时间吗。Sleep仅保证线程至少在指定的时间内睡眠。如果ThreadA和ThreadB同时进入睡眠状态,不能保证他们会以相反的顺序醒来。只是好奇——为什么要用BeginInvoke来执行这个动作?如果我理解正确,为什么不直接将操作中的代码放在第一个回调中,并在最后调用OnTaskComplete,因为回调在另一个线程上已经是异步的?@raj。我想知道的是,为什么这些线程一个接一个地缓慢启动?启动这些线程大约需要10秒。我想应该分批开始。好吧,顺序不重要。但是我们可以看到一些线程在5秒后启动!。这不是平行启动。我认为100毫秒后的最新一次启动是可以接受的。我想如果cpu内核的数量少于线程,线程将按时间片进行。我确实发现前两个线程同时启动,但第三个、第四个线程在1秒或2秒后继续运行,这似乎很长。也许这条线索。睡眠不能很好地分割时间。不,你错过了答案的关键部分。线程池管理器防止线程在内核繁忙时启动。实际上,我试图在进行单元测试时模拟I/O请求等待场景。我找不到比使用thread.sleep更好的方法了。这是对threadpool调度队列的一个ok模拟,该队列由被阻塞的线程备份。线程池管理器将不会启动超过最小配置线程数的线程,直到确定排队的代理无法足够快地得到服务。
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);