You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

控制台应用使用Thread.Sleep无等待效果?输出时间均相同

控制台命令执行等待逻辑异常问题解决

问题说明

开发的控制台应用未按预期实现等待逻辑,所有命令输出时间几乎一致。需求如下:

  • 命令按顺序执行,必须等待上一个命令的WaitAfterExecution完成后再执行下一个命令
  • 允许长时间数据获取类任务并行执行

使用Thread.Sleep未达到预期效果,尝试单独线程执行也无效,相关代码、示例及输出如下:

原代码实现

命令定义与扩展方法

public class Qsend: IQCommand
{
    public Qsend(Action p, int v1, int v2, string v3)
    {
        OnCommand = p;
        WaitBeforeExecution = v1;
        WaitAfterExecution = v2;
        Name = v3;
    }

    public Action OnCommand { get ; set ; }
    public int WaitBeforeExecution { get ; set ; }
    public int WaitAfterExecution { get ; set ; }
    public string Name { get ; set ; }
}

public interface IQCommand
{
    Action OnCommand { get; set; }
    int WaitBeforeExecution { get; set; }
    int WaitAfterExecution { get; set; }
    string Name { get; set; }
}

public static class CExtensions
{
    public static void ProcessThis(this IQCommand irc)
    {
        Console.WriteLine("Process This Started!!!");
        if (irc == null)
            return;

        if (irc.OnCommand == null)
            return;

        if (irc.WaitBeforeExecution > 0)
            System.Threading.Thread.Sleep(irc.WaitBeforeExecution);

        irc.OnCommand.Invoke();

        if (irc.WaitAfterExecution > 0)
            System.Threading.Thread.Sleep(irc.WaitAfterExecution);
        Console.WriteLine("Process This End!!!");
    }
}

使用示例

using System.Diagnostics;

List<IQCommand> commands = new List<IQCommand>();

commands.Add(new Qsend(() => { Console.WriteLine($"Command 1 {DateTime.Now.ToString(\"HH:mm:ss.ffffff\")}"); }, 3, 6, "Name 1"));
commands.Add(new Qsend(() => { Console.WriteLine($"Command 2 { DateTime.Now.ToString(\"HH:mm:ss.ffffff\")}"); }, 5, 10, "Name 2"));

Console.WriteLine($"Before EXE {DateTime.Now.ToString(\"HH:mm:ss.ffffff\")}");
foreach (var item in commands)
{
    Console.WriteLine(item.Name);
    item.ProcessThis();
}
Console.WriteLine($"AFTER EXE {DateTime.Now.ToString(\"HH:mm:ss.ffffff\")}");

实际输出

Before EXE 15:11:13.482163
Name 1
Process This Started!!!
Command 1 15:11:13.533112
Process This End!!!
Name 2
Process This Started!!!
Command 2 15:11:13.563431
Process This End!!!
AFTER EXE 15:11:13.578287

尝试过的线程方案

Thread thr = new Thread(new ThreadStart(() => {
    Console.WriteLine($"Before EXE {DateTime.Now.ToString(\"HH:mm:ss.ffffff\")}");
    foreach (var item in commands)
    {
        Console.WriteLine(item.Name);
        item.ProcessThis();
    }
    Console.WriteLine($"AFTER EXE {DateTime.Now.ToString(\"HH:mm:ss.ffffff\")}");
}));
thr.Start();

问题根源与解决方案

问题根源

  1. 等待参数值过小:示例中传入的WaitBeforeExecution和WaitAfterExecution为3、6、5、10,这些是毫秒级数值,时间间隔极短,导致视觉上几乎同时执行。
  2. 阻塞式等待:Thread.Sleep会阻塞当前线程,无法实现非阻塞的等待,也不利于并行执行长时间任务。
  3. 不支持异步逻辑:原代码使用Action,无法直接处理异步任务,限制了并行场景的实现。

修改后的实现

1. 调整命令接口与类,支持异步

public interface IQCommand
{
    Func<Task> OnCommand { get; set; }
    int WaitBeforeExecution { get; set; }
    int WaitAfterExecution { get; set; }
    string Name { get; set; }
}

public class Qsend : IQCommand
{
    public Qsend(Func<Task> p, int v1, int v2, string v3)
    {
        OnCommand = p;
        WaitBeforeExecution = v1;
        WaitAfterExecution = v2;
        Name = v3;
    }

    public Func<Task> OnCommand { get; set; }
    public int WaitBeforeExecution { get; set; }
    public int WaitAfterExecution { get; set; }
    public string Name { get; set; }
}

2. 异步扩展方法,非阻塞等待

public static class CExtensions
{
    public static async Task ProcessThisAsync(this IQCommand irc)
    {
        Console.WriteLine("Process This Started!!!");
        if (irc == null || irc.OnCommand == null)
            return;

        if (irc.WaitBeforeExecution > 0)
            await Task.Delay(irc.WaitBeforeExecution);

        // 异步执行命令逻辑,支持并行任务
        await irc.OnCommand.Invoke();

        if (irc.WaitAfterExecution > 0)
            await Task.Delay(irc.WaitAfterExecution);
            
        Console.WriteLine("Process This End!!!");
    }
}

3. 最终使用示例(顺序执行+并行任务)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        List<IQCommand> commands = new List<IQCommand>();

        // 命令1:包含并行数据获取任务
        commands.Add(new Qsend(async () => 
        { 
            Console.WriteLine($"Command 1 {DateTime.Now.ToString("HH:mm:ss.ffffff")}");
            // 模拟长时间并行数据获取,后台线程执行
            var dataFetchTask = Task.Run(() => 
            {
                Thread.Sleep(5000); // 模拟5秒数据获取
                Console.WriteLine($"Command 1 数据获取完成 {DateTime.Now.ToString("HH:mm:ss.ffffff")}");
            });
            // 此处可继续执行同步逻辑,无需等待数据任务完成
            // await dataFetchTask; // 若需等待数据获取完成再继续,取消注释
        }, 3000, 6000, "Name 1"));

        // 命令2:普通同步命令
        commands.Add(new Qsend(() => 
        { 
            Console.WriteLine($"Command 2 {DateTime.Now.ToString("HH:mm:ss.ffffff")}");
        }, 5000, 10000, "Name 2"));

        Console.WriteLine($"Before EXE {DateTime.Now.ToString("HH:mm:ss.ffffff")}");
        // 顺序执行每个命令,等待上一个完成再执行下一个
        foreach (var item in commands)
        {
            Console.WriteLine(item.Name);
            await item.ProcessThisAsync();
        }
        Console.WriteLine($"AFTER EXE {DateTime.Now.ToString("HH:mm:ss.ffffff")}");
    }
}

修改说明

  • 将Action改为Func<Task>,支持异步命令逻辑,便于处理并行任务
  • 用Task.Delay替代Thread.Sleep,实现非阻塞等待,避免占用线程资源
  • 长时间数据获取任务通过Task.Run放到后台线程执行,实现并行处理
  • 主方法改为async Task Main,支持异步等待,确保命令按顺序执行

内容的提问来源于stack exchange,提问作者Dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 11:20:34