簡體   English   中英

如何避免異步方法使用新線程?

[英]How avoid async method to use new thread?

我讀過await / async不應創建/使用新線程,但編譯器會在后台創建astate machien。...所以我嘗試了此操作,每次對F1的調用都使用ThreadPool中的線程。

class Program
{
    static System.Threading.SemaphoreSlim sem =
        new System.Threading.SemaphoreSlim(20, 20);
    static async void F1()
    {
        await sem.WaitAsync();
        await sem.WaitAsync();
        await Task.Delay(6000);
        var threadId = GetCurrentThreadId();
        sem.Release();
        sem.Release();
    }

    static void Main(string[] args)
    {
        var threadId = GetCurrentThreadId();

        F1();
        F1();
        F1();
        F1();
        F1();
        F1();
        F1();
        F1();
        Task.Delay(30000).Wait();
    }
    [DllImport("kernel32.dll")]
    static extern uint GetCurrentThreadId();

}

您已經使用了await Task.Delay(6000) ,它保證不會同步完成,因此:完成將通過任何可能的方式(通常是線程池)返回(因為此處沒有同步上下文)。 只要您不長時間捆綁線程池線程,它就很便宜。 如果所做的只是捕獲當前線程ID並釋放,則它們實際上應該在啟動后立即完成。

代碼需要在某個地方運行; 希望它在哪個線程上運行? 您的主線程當前處於阻塞的Wait()調用中,因此它無法執行任何操作。 注意:您幾乎永遠不要在不完整的Task上調用.Wait()

經過一番研究,我找到了想要的答案。 https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/

實際上Mrinal Kamboj在我的問題上添加了一條評論,指出了正確的方向。 我需要為繼續運行創建一個同步上下文 此代碼段還顯示了為什么您不應該對未完成的任務使用Wait():如果繼續在同一線程上運行(對於GUI線程或ASP.NET發生),如果該線程被鎖定以等待繼續,那么我們將在死機中運行-鎖定情況。

class Program
{
    static System.Threading.SemaphoreSlim Semaphore = new System.Threading.SemaphoreSlim(3, 3);
    static async Task F(int i)
    {
        Console.WriteLine($"F{i} starts on " + GetCurrentThreadId());
        await Semaphore.WaitAsync();
        Console.WriteLine($"F{i} continues on " + GetCurrentThreadId());
        await Task.Delay(6000);     //.ConfigureAwait(false); //<- uncomment to solve deadlock
        Console.WriteLine($"F{i} ends on " + GetCurrentThreadId());
        Semaphore.Release(1);
        //DeadLock();
    }

    static void DeadLock()
    {
        F(70).Wait();
    }

    static void Main(string[] args)
    {
        var context = new SingleThreadSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(context); 
        for (int i = 0; i < 10; i++)
        {
            int ind = i;
            F(ind);
        }
        context.RunOnCurrentThread();
    }

    [DllImport("kernel32.dll")]
    static extern uint GetCurrentThreadId();

}


sealed class SingleThreadSynchronizationContext : SynchronizationContext
{

    private readonly Thread Thread = Thread.CurrentThread;


    public override void Post(SendOrPostCallback d, object state)
    {
        if (d == null)
            throw new ArgumentNullException("d");

        WorkItemsQueue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
    }


    public override void Send(SendOrPostCallback d, object state)
    {
        throw new NotSupportedException("Synchronously sending is not supported.");
    }


    public void RunOnCurrentThread()
    {
        foreach (var workItem in WorkItemsQueue.GetConsumingEnumerable())
            workItem.Key(workItem.Value);
    }


    public void Complete() { WorkItemsQueue.CompleteAdding(); }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM