从非异步运行async()而不等待

时间:2015-05-06 14:48:51

标签: c# multithreading asynchronous

在我的代码中为什么QueueTasks()不能与main方法一起运行asyncronusly?是否有不同的方式来调用呢?

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

当我谷歌从非异步运行异步时,一切建议使用Task.Wait(),但我不想等,我只是想触发这个过程。我也谷歌搜索主线程异步,但发现了相互矛盾的建议,所以我不确定这里究竟是什么问题。我正在使用.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();
    }
}

1 个答案:

答案 0 :(得分:4)

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

如果您在某个时候使用过await,那么QueueTasks将会返回,您可以继续执行Main

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

您可以做的最简单的事情就是将QueueTasks方法包装在Task.Run中。这将使它在与被调用者平行的新线程上运行。

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

最难的是实际学习如何使用并行执行和限制来正确处理生产者 - 消费者队列。同样,http://www.albahari.com/threading/是一个伟大的首发:)