简体   繁体   English

在BeginInvoke()中调用异步方法会产生一个'新'线程吗?

[英]Does calling an async method within BeginInvoke() spawn a 'new' thread?

'New' meaning from a thread pool. 线程池中的“新”含义。

Given the example below, my assumptions are: 鉴于以下示例,我的假设是:

  1. Main method executes on one thread (eg. thread 1) 主方法在一个线程上执行(例如,线程1)
  2. BeginInvoke uses available thread in pool to execute AsyncDemo.TestMethod (thread 2) BeginInvoke使用池中的可用线程来执行AsyncDemo.TestMethod(线程2)
  3. An async method call, eg WebClient.UploadStringAsync uses another available thread (thread 3) 异步方法调用,例如WebClient.UploadStringAsync使用另一个可用线程(线程3)

Number three is where my question stems from, The definition of WebClient.UploadStringAsync: Uploads the specified string to the specified resource. 第三个是我的问题源于的地方,WebClient.UploadStringAsync的定义:将指定的字符串上传到指定的资源。 These methods do not block the calling thread. 这些方法不会阻止调用线程。

Does this mean it uses another available thread in the pool? 这是否意味着它使用池中的另一个可用线程? Is this an ill-advised technique (async within an async)? 这是一种不明智的技术(异步中的异步)吗?

My ultimate goal is to post some data asynchronously (fire and forget), and was using UploadStringAsync previously. 我的最终目标是异步发布一些数据(触发并忘记),并且之前使用的是UploadStringAsync。 Now I have decided to encapsulate the surrounding code with BeginInvoke as well, but thinking if I have to change the UploadStringAsync to a synchronous method instead (UploadString()). 现在我决定用BeginInvoke封装周围的代码,但是想一想我是否必须将UploadStringAsync更改为同步方法(UploadString())。

Thanks for any help! 谢谢你的帮助!

public class AsyncMain 
{
    // The delegate will be called asynchronously.
    public delegate string AsyncMethodCaller(out int threadId);

    public static void Main() 
    {       
        // The asynchronous method puts the thread id here.
        int threadId;       

        //Create the delegate.
        AsyncMethodCaller caller = new AsyncMethodCaller(AsyncDemo.TestMethod);

        // Initiate the asychronous call.
        IAsyncResult result = caller.BeginInvoke(out threadId, null, null);     

        Console.WriteLine("In AsyncMain.Main() Thread {0} does some work.", Thread.CurrentThread.ManagedThreadId);

        // Call EndInvoke to wait for the asynchronous call to complete,
        // and to retrieve the results.
        string returnValue = caller.EndInvoke(out threadId, result);

        Console.WriteLine("The async call executed on thread {0}, has responded with \"{1}\". The result is {2}", threadId, returnValue, result);
    }
}


public class AsyncDemo 
{   
    // The method to be executed asynchronously.
    public static string TestMethod(out int threadId) 
    {
        //get threadId, assign it.
        threadId = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("TestMethod() begins at thread {0}", threadId);

        //Do work

        //Do ASYNC Method such as: WebClient.UploadStringAsync

        return String.Format("I'm finished my work.");
    }
}

Does this mean it uses another available thread in the pool? 这是否意味着它使用池中的另一个可用线程?

Short answer: yes. 简短回答:是的。

  1. According to the docs for UploadStringAsync: 根据UploadStringAsync的文档:

    The string is sent asynchronously using thread resources that are automatically allocated from the thread pool. 使用从线程池自动分配的线程资源异步发送字符串。

  2. And BeginInvoke uses a thread from the thread pool to accomplish its asynchronous behavior. BeginInvoke 使用线程池中的线程来完成其异步行为。

Is this an ill-advised technique (async within an async)? 这是一种不明智的技术(异步中的异步)吗?

If you need asynchronous behavior at both levels, then you do what you gotta do. 如果您需要在两个级别上进行异步行为,那么您可以执行您必须执行的操作。 In general, though, the best advice is to write the simplest code you can that will work, so if you can get away with just one level of indirection, I'd say go for it. 但总的来说,最好的建议是编写最简单的代码,这样就可以使用,所以如果你只能通过一个间接层来逃避,我会说它去做。

It's unfortunate that you can't upgrade to a newer version of .NET, because with newer versions you can accomplish the same thing much more simply using Tasks: 遗憾的是,您无法升级到较新版本的.NET,因为对于较新版本,您可以使用任务更简单地完成相同的操作:

public static void Main() 
{       
    Task<string> task = AsyncDemo.TestMethod();

    Console.WriteLine("In AsyncMain.Main() Thread {0} does some work.", Thread.CurrentThread.ManagedThreadId);

    string returnValue = task.Result; // This will cause the main thread to block until the result returns.

    Console.WriteLine("The async call executed on thread {0}, has responded with \"{1}\". The result is {2}", threadId, returnValue, result);
}



public class AsyncDemo 
{   
    // The method to be executed asynchronously.
    public async static Task<string> TestMethod() 
    {
        Console.WriteLine("TestMethod() begins");

        //Do work

        await new WebClient().UploadStringTaskAsync("...", "...");

        return String.Format("I'm finished my work.");
    }
}

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

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