简体   繁体   中英

How avoid async method to use new thread?

I have read that await/async should not create/use new threads but the compiler creates a astate machien under the hood....so i tried this, and each call to F1 uses a thread from the 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();

}

You've used await Task.Delay(6000) , which is guaranteed to not complete synchronously, so: the completion will come back via whatever it can - typically the thread-pool (since there's no sync-context in play here). Thread pool threads are cheap as long as you don't tie them up for extended periods; if all it does is capture the current thread id and release, they should all be complete virtually immediately after they fire.

The code needs to run somewhere ; what thread would you expect it to run on? Your main thread is currently in a blocking Wait() call, so it can't do anything. Note: you should almost never call .Wait() on an incomplete Task .

After some research, i found the answer i was looking for. https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/

Actually Mrinal Kamboj added a comment, to my question, pointing to the right direction. I needed to create a synchronization context for the continuations to run on. This snippet also shows why you should not Wait() on incomplete task: if the continuation runs on the same thread (which happens for GUI threads or ASP.NET) , if this thread is locked waiting for continuation then we run in a dead-lock situation.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM