简体   繁体   English

在后台线程上运行异步函数?

[英]Run async function on background thread?

I'm working on a project that includes a server and a client.我正在开发一个包含服务器和客户端的项目。 The client sends every second a UDP packet to the server, and according to the server's response it might open a TCP connection with the server (and recieve files from the server), the client's program has a GUI which I don't want to block (made in WPF MVVM), and also it's problematic to start async function on constructor of the MainWindow as constructors can't be async.客户端每秒向服务器发送一个 UDP 数据包,根据服务器的响应,它可能会打开与服务器的 TCP 连接(并从服务器接收文件),客户端的程序有一个我不想阻止的 GUI (在 WPF MVVM 中制作),并且在 MainWindow 的构造函数上启动异步函数也是有问题的,因为构造函数不能是异步的。 So my question is, can I and should I run async functions on a background thread?所以我的问题是,我可以并且应该在后台线程上运行异步函数吗? Does the async improve performance if it's on a background thread, I'm talking about the difference between these options:如果异步在后台线程上会提高性能,我说的是这些选项之间的区别:

public MainWindow()
{
    InitializeComponent();
    DirectoryViewModel DirectoryVM = new DirectoryViewModel();
    this.DataContext = DirectoryVM;
    DirectoryVM.StartListen(); //Unwanted as constructor won't finish
}

To

public MainWindow()
{
    InitializeComponent();
    DirectoryViewModel DirectoryVM = new DirectoryViewModel();
    this.DataContext = DirectoryVM;
    Task.Run(DirectoryVM.StartListen()); //Possible but async might be faster
}

To

public MainWindow()
{
    InitializeComponent();
    DirectoryViewModel DirectoryVM = new DirectoryViewModel();
    this.DataContext = DirectoryVM;
    Task.Run(async () => await DirectoryVM.StartListenAsync()); //Is it faster than the second option?
}

From what I've seen I shouldn't run async code on background thread like this, but why?从我所见,我不应该像这样在后台线程上运行异步代码,但为什么呢? Isn't it faster than running sync code on a background thread?它不是比在后台线程上运行同步代码更快吗? Also I guess it's not really different but on my server I'll create a constant running thread that listens for tcp connections and will send files over it, should I make the send file function async or not?此外,我想它并没有真正不同,但在我的服务器上,我将创建一个持续运行的线程来侦听 tcp 连接并通过它发送文件,我应该使发送文件功能异步吗?

Thanks!谢谢!

... is it ok to start async method on a seperate thread ... ...可以在单独的线程上启动异步方法吗...

I think you fundamentally misunderstand the async methods.我认为您从根本上误解了异步方法。 Calling an async method does not create a new thread or offload the entire method onto any other thread.调用异步方法不会创建新线程或将整个方法卸载到任何其他线程。 Calling an async method is like calling any other method, but it maybe at some point returns execution back to the caller (with a Task as a promise) and finishes its remaining job at some point.调用异步方法就像调用任何其他方法一样,但它可能在某个时候将执行返回给调用者(以 Task 作为承诺)并在某个时候完成其剩余的工作。

Though it is possible to spin up an always running periodic listener using async method, it is rather against its purpose.尽管可以使用 async 方法启动一个始终运行的定期侦听器,但这与它的目的背道而驰。

When you call an async method, you expect it will be run to completion within a reasonable time (hence why you want to await on it), but it might takes long enough time to do something else meanwhile.当您调用异步方法时,您希望它会在合理的时间内运行完成(因此您要等待它),但同时可能需要足够长的时间来执行其他操作。 In your case, you should explicitly start a new background task or thread what does the periodic check for you.在您的情况下,您应该明确启动一个新的后台任务或线程定期检查什么。 It can be a new thread or better, a new task (Task.Run for example).它可以是一个新线程或更好的新任务(例如 Task.Run)。

From what I've seen I shouldn't run async code on background thread like this, but why?从我所见,我不应该像这样在后台线程上运行异步代码,但为什么呢?

According to your comments the DirectoryVM.StartListen() starts the constantly running listening, what does not have to be async.根据您的评论DirectoryVM.StartListen()开始不断运行的侦听,不必是异步的。 Unless it does any async calls, it is not something awaitable.除非它进行任何异步调用,否则它不是可等待的。

Isn't it faster than running sync code on a background thread?它不是比在后台线程上运行同步代码更快吗?

Async is not about speed, but about thread blocking.异步不是关于速度,而是关于线程阻塞。 It does not matter if the thread is foreground or background, using async method for an I/O operation, like calling an http endpoint or sending a UDP packet is always beneficial, if the thread can do other things while waiting, or otherwise blocking that thread might cause other issues.线程是前台还是后台都没有关系,使用异步方法进行 I/O 操作,例如调用 http 端点或发送 UDP 数据包总是有益的,如果线程在等待时可以做其他事情,或者以其他方式阻止它线程可能会导致其他问题。

Also I guess it's not really different but on my server I'll create a constant running thread that listens for tcp connections and will send files over it, should I make the send file function async or not?此外,我想它并没有真正不同,但在我的服务器上,我将创建一个持续运行的线程来侦听 tcp 连接并通过它发送文件,我应该使发送文件功能异步吗?

You should, if it is beneficial.你应该,如果它是有益的。 See previous part.见上一部分。

From what I've seen I shouldn't run async code on background thread like this, but why?从我所见,我不应该像这样在后台线程上运行异步代码,但为什么呢?

I'm not aware of any recommendations not to run asynchronous code with Task.Run .我不知道有任何建议不要使用Task.Run运行异步代码。

Task.Run should be avoided on ASP.NET (for both synchronous and asynchronous code), but that doesn't apply here since you have a GUI app. Task.Run应该避免在 ASP.NET 上(对于同步和异步代码),但这不适用于这里,因为您有一个 GUI 应用程序。

Isn't it faster than running sync code on a background thread?它不是比在后台线程上运行同步代码更快吗?

No. The code will not be any faster.不。代码不会更快。 async is about freeing up threads, not running faster. async是关于释放线程,而不是运行得更快。

I think the concern that you've seen is that of ignoring tasks.我认为您所看到的担忧是忽略任务。 Using Task.Run and ignoring the task it returns is problematic because that's a form of fire-and-forget.使用Task.Run并忽略它返回的任务是有问题的,因为这是一种即发即忘的形式。 So if your loop fails due to an exception, your application would never know.因此,如果您的循环因异常而失败,您的应用程序将永远不会知道。 One way around this is to await the task from an async void method.解决此问题的一种方法是await来自async void方法的任务。 For example, as your Window's Initialized event handler:例如,作为您的 Window 的Initialized事件处理程序:

async void Window_Initialized(object, EventArgs)
{
  await Task.Run(DirectoryVM.StartListen);
  // or, if asynchronous:
  await DirectoryVM.StartListenAsync();
}

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

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