【问题标题】:Does calling an async method within BeginInvoke() spawn a 'new' thread?在 BeginInvoke() 中调用异步方法会产生一个“新”线程吗?
【发布时间】:2014-08-08 22:29:30
【问题描述】:

来自线程池的“新”含义。

鉴于下面的例子,我的假设是:

  1. Main 方法在一个线程(例如线程 1)上执行
  2. BeginInvoke 使用池中的可用线程来执行 AsyncDemo.TestMethod(线程 2)
  3. 异步方法调用,例如 WebClient.UploadStringAsync 使用另一个可用线程(线程 3)

第三个问题是我的问题源于WebClient.UploadStringAsync的定义:将指定的字符串上传到指定的资源。这些方法不会阻塞调用线程。

这是否意味着它使用了池中的另一个可用线程?这是一种不明智的技术(异步中的异步)吗?

我的最终目标是异步发布一些数据(即发即忘),并且之前使用的是 UploadStringAsync。现在我决定也用 BeginInvoke 封装周围的代码,但考虑是否必须将 UploadStringAsync 更改为同步方法(UploadString())。

感谢您的帮助!

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.");
    }
}

【问题讨论】:

  • 您有什么理由不使用 TPL 方法吗?
  • 抱歉,我忽略了我在 .NET 3.5 上(在 MSDN 上指出它仅适用于 4 和 4.5)。幸运的是,我在 nuget 上看到了一些关于 .NET 3.5 的 TPL 的内容,但不幸的是,我目前无法向项目引入新的包。
  • 对于其他人,您可以使用包管理器命令“Install-Package TaskParallelLibrary”导入 3.5 的 TPL 包。您甚至可以在 Tasks 中包装 APM 方法(开始/结束)。

标签: c# multithreading asynchronous begininvoke


【解决方案1】:

这是否意味着它使用了池中的另一个可用线程?

简短的回答:是的。

  1. 根据 UploadStringAsync 的文档:

    使用从线程池自动分配的线程资源异步发送字符串。

  2. 然后 BeginInvoke uses a thread from the thread pool 完成其异步行为。

这是一种不明智的技术(异步中的异步)吗?

如果您在两个级别都需要异步行为,那么您就做您该做的。不过,一般来说,最好的建议是编写可以工作的最简单的代码,所以如果你可以只使用一级间接,我会说去吧。

很遗憾,您无法升级到较新版本的 .NET,因为使用较新版本,您可以更简单地使用 Tasks 完成同样的事情:

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.");
    }
}

【讨论】:

  • 还应注意,在 BeginInvoke/EndInvoke 调用中包装 UploadStringAsync 不会使行为“阻塞”。 UploadStringAsync 将在线程上执行,与 BeginInvoke 线程没有任何关系或同步。但是,是的,TPL 或 async/await 会好得多。
  • 是的,我很想升级 .NET,但我们正在维护一个遗留项目,其中包含我不想接触的无数移动部件 :)。不过谢谢你的回复!
猜你喜欢
  • 1970-01-01
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多