简体   繁体   English

C#多线程与异步/等待结合

[英]C# multithreading combined with async/await

This is yet another question related to multi-threading in C#. 这是与C#中的多线程有关的另一个问题。

However, when multi-threading combined with async/await seems to be interesting. 但是,当多线程与异步/等待相结合时似乎很有趣。

I have a method generating threads which invoke methods of objects asynchronously. 我有一个生成线程的方法,该线程异步调用对象的方法。

However, the context is not shared by objects of different classes. 但是,上下文不被不同类的对象共享。

For example, consider the code 例如,考虑代码

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

namespace ThreadDataSharing
{
    class Data
    {
        public static ThreadLocal<string> Name = new ThreadLocal<string>();
    }

    class Locker { public static object lobj = new object { };}
    class Program2
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                var pObj = new Program();
                new Thread(new ThreadStart(pObj.MyThreadMethod)).Start();
            }
        }
    }
    class Program
    {

        ///my async method
        ///
        public async Task MyAsyncMethod()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From async method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            await MyAsyncMethod2();

            await new AsyncClass().AsyncMethod();
        }

        public async Task MyAsyncMethod2()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From async 2 method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            await Task.Run(() =>
            {
                lock (Locker.lobj)
                {
                    Console.WriteLine("From task run method");
                    Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine("id: " + Data.Name.Value);
                }
            });
        }

        public void MyThreadMethod()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From thread method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);

                var id = Guid.NewGuid();
                Data.Name.Value = id.ToString();
                Console.WriteLine("id: " + Data.Name.Value);
            }

            MyAsyncMethod().Wait();
        }
    }


    public class AsyncClass
    {
        public async Task AsyncMethod()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From class async method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            var newId = Guid.NewGuid();
            Data.Name.Value = newId.ToString();

            await AsyncMethod2();
        }

        public async Task AsyncMethod2()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From class async 2 method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            await Task.Run(() => { });
        }
    }

}

Running this code produces the following output on my machine 运行此代码在我的机器上产生以下输出

From thread method
thread: 3
id: 3a7ef8e3-ebe1-49e1-94bb-798358ac1567
From thread method
thread: 4
id: 341d3371-f905-4e1c-aac3-47bda16c8d88
From thread method
thread: 5
id: b7e79901-81b7-430f-b158-59f091e43a0c
From async method
thread: 3
id: 3a7ef8e3-ebe1-49e1-94bb-798358ac1567
From async method
thread: 5
id: b7e79901-81b7-430f-b158-59f091e43a0c
From async method
thread: 4
id: 341d3371-f905-4e1c-aac3-47bda16c8d88
From async 2 method
thread: 3
id: 3a7ef8e3-ebe1-49e1-94bb-798358ac1567
From async 2 method
thread: 4
id: 341d3371-f905-4e1c-aac3-47bda16c8d88
From async 2 method
thread: 5
id: b7e79901-81b7-430f-b158-59f091e43a0c
From task run method
thread: 6
id:
From task run method
thread: 8
id:
From task run method
thread: 7
id:
From class async method
thread: 7
id:
From class async method
thread: 6
id:
From class async method
thread: 8
id:
From class async 2 method
thread: 8
id: f52ed654-0e55-4906-bfc1-65c6b25a7785
From class async 2 method
thread: 7
id: 1e53e03b-a3a0-4296-8622-7716b45d1462
From class async 2 method
thread: 6
id: 1adca81d-b11a-4860-b37d-a017afe877b8

Question is, why is it not sharing the ThreadLocal<T> object with the instance of the second Class ( AsyncClass )? 问题是,为什么它不与第二个类( AsyncClass )的实例共享ThreadLocal<T>对象?

在具有await / async的控制台应用程序中,没有共享的同步上下文,这可能是不共享同步上下文的原因。

the context is not shared by objects of different classes. 上下文不被不同类的对象共享。

Actually, the behavior you're seeing is that the (thread-local) context is not shared between threads . 其实,你所看到的行为是(线程本地)上下文不线程之间共享。

I have an async intro blog post that may clear up this behavior. 我有一个异步介绍博客文章,可能会解决此问题。 The essential concept is that async methods do not resume on the same thread ; 基本概念是async方法不能在同一线程上恢复; rather, they resume on a captured context (by default). 相反,它们在捕获的上下文中恢复(默认情况下)。 In this case, the thread pool context is used to resume your async methods, which means that those continuations are just scheduled to the thread pool, and may be run by any thread pool thread. 在这种情况下,线程池上下文用于恢复您的async方法,这意味着这些延续只是安排在线程池中,并且可以由任何线程池线程运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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