运行 来自非异步的 async() 无需等待

Running async() from non async without waiting

在我的代码中,为什么 QueueTasks() 不 运行 与 main 方法异步?是否有不同的调用方式?

我希望QueueTasks(thingsToProcess, cts.Token);启动异步方法,然后继续执行代码。

当我从非异步 google 运行 宁异步时,一切都建议使用 Task.Wait() 但我不想等待,我只想触发该过程。我也 googled 使主线程异步,但发现了相互矛盾的建议,所以我不确定这里的确切问题是什么。我正在使用 .net 4.5。

class Program
{
    private static SemaphoreSlim maxThreads = new SemaphoreSlim(5);
    private static readonly object syncLock = new object();
    private static readonly Random getrandom = new Random();
    private static int inQueue = 0;
    public static int GetRandomNumber(int min, int max)
    {
        lock (syncLock)
        { // synchronize
            return getrandom.Next(min, max);
        }
    }
    static async Task DoSomething(string input, int row, SemaphoreSlim theSem)
    {
        theSem.Wait();
        inQueue++;
        int delay = GetRandomNumber(0, 5000);
        await Task.Delay(delay);
        Console.WriteLine(String.Format("{0}: Doing something to {1}", row,input));
        inQueue--;
        theSem.Release();

    }
    static async Task QueueTasks(List<string> things, CancellationToken ct)
    {
            int taskNumber = 0;
            foreach (string thing in things)
            {
                if (ct.IsCancellationRequested)
                {
                    Console.WriteLine("No more tasks being queued");
                    break;
                }
                else
                {
                    maxThreads.Wait();
                    DoSomething(thing, ++taskNumber, maxThreads);
                    maxThreads.Release();
                }
            }
    }

    static void Main(string[] args)
    {

        // build list of 100 random strings to represent input
        List<string> thingsToProcess = new List<string>();
        for (int i = 0; i < 100; i++)
        {
            thingsToProcess.Add(Path.GetRandomFileName());
        }
        Console.WriteLine("Starting queue");

        CancellationTokenSource cts = new CancellationTokenSource();

        // I want this to initiate a queue starting but not stop the flow of code.
        QueueTasks(thingsToProcess, cts.Token);           

        // This should run immediately after queue starts   
        Console.WriteLine("Hit X to stop current queue"); 
        ConsoleKeyInfo cancel = Console.ReadKey();

        while (cancel.KeyChar != 'x')
        {
            cancel = Console.ReadKey();
        }

        if (cancel.KeyChar == 'x')
        {
            cts.Cancel();
            Console.WriteLine(String.Format("You requested a cancellation. {0} threads left to process", inQueue));
        }
        else
        {
            Console.WriteLine("Operation completed without interuption");
        }

        Console.ReadLine();
    }
}

async 不是神奇地使您的方法异步的关键字!它只允许您在其中使用 await 关键字 - 您没有这样做。您的方法是完全同步的,因此它不会 return 直到完成。

如果您确实在某个时候使用了 await,那时候 QueueTasks 会 return,您可以继续执行 Main.

除此之外,你的代码是线程不安全的,所以你很幸运它实际上没有 运行 多线程(实际上,它在多个线程上 运行 - 但是一次至少只有大约 2-3 个线程):) 一个很好的多线程入门是 http://www.albahari.com/threading/.

最简单的方法就是将 QueueTasks 方法包装在 Task.Run 中。这将导致它 运行 在一个新线程上,与被调用者并行。

第二个最简单的方法是在 QueueTasks 中使用 await,当您使用 "waiting" 作为信号量时 - await maxThreads.WaitAsync() 而不是 maxThreads.Wait .请注意,您应该删除 DoSomething 内部的等待 - 您正在丢弃信号量槽;实际上很有可能像这样死锁你的代码(所有五个插槽都被外部 Wait 占用,这将阻止 DoSomething 中的 Wait 解锁)。

最难的事情是实际学习如何通过并行执行和节流来正确处理生产者-消费者队列。同样,http://www.albahari.com/threading/ 是一个很好的开始 :)