gpt4 book ai didi

c# - 何时使用 Task.Run 而不是

转载 作者:行者123 更新时间:2023-11-30 13:29:43 25 4
gpt4 key购买 nike

我问这个question昨天还是不明白使用的区别

task = Task.Run(() => RunLongRunningMethod(cts.Token));

task = RunLongRunningMethod(cts.Token);

我已通读 Task.Run Etiquette and Proper Usage并且它似乎主要使用 Task.Run 只要它被正确使用(不在实现中)

有没有关于此的任何其他阅读 Material ,或者有人可以解释两者之间的区别吗?

我的代码在下面,使用这两种方法都可以正常工作。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private static HttpClient client { get; set; }
private Task task { get; set; }
private CancellationTokenSource cts { get; set; }
private bool buttonStartStopState { get; set; }

public Form1()
{
InitializeComponent();
}

private async Task RunLongRunningMethod(CancellationToken cancellationToken)
{
try
{
while (true)
{
if (cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}

// Some CPU bound work here

// Then call async
var success = await GetUrlAsync(@"https://www.bbc.co.uk/");
Thread.Sleep(2000); // simulate blocking only
}
}
catch (OperationCanceledException)
{
// Just exit without logging. Operation cancelled by user.
}
catch (Exception ex)
{
// Report Error
}
}

private async Task<bool> GetUrlAsync(string url)
{
if (client == null)
{
client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip });
client.BaseAddress = new Uri("https://www.bbc.co.uk/");
client.DefaultRequestHeaders.Add("Accept", "*/*");
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/62.0");
client.DefaultRequestHeaders.Connection.Add("Keep-Alive");
client.DefaultRequestHeaders.Add("DNT", "1");
}

var response = await client.GetAsync(url);
var contents = await response.Content.ReadAsStringAsync();

Debug.WriteLine($"{DateTime.Now} {response.StatusCode}");
return true;
}

private void buttonStartStop_Click(object sender, EventArgs e)
{
buttonStartStopState = !buttonStartStopState;
if(buttonStartStopState)
{
cts = new CancellationTokenSource();

// What is difference between this
//task = Task.Run(() => RunLongRunningMethod(cts.Token));

// And this?
task = RunLongRunningMethod(cts.Token);

// This always runs instantly
Debug.WriteLine($"{DateTime.Now} buttonStartStopState:{buttonStartStopState}");
}
else
{
cts.Cancel();
cts = null;
}
}

private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(cts != null)
{
cts.Cancel(); // CancellationTokenSource
cts = null;
}

if (!task.IsCompleted)
{
//this.Hide();
e.Cancel = true;
await task;
this.Close();
}
}
}
}

最佳答案

基本上,使用 async/await 贯穿 您的代码库,这样就没有什么阻塞 线程了。 (例如,正如我评论的那样,您当前对 Thread.Sleep 的使用是阻塞的)。

一旦达到这一点,您就已经很热了 Task s 由您的异步函数返回,这些函数将在它们没有取得进一步进展时立即返回。

此时,您需要做出决定。您是否有一项长时间运行的任务受 CPU 限制?如果是这样, 就是您可以考虑使用 Task.Run 的时候了,因为这明确要求在其他地方(线程池)完成工作。允许 I/O 主导的任务短暂地返回到 UI 线程通常ok,这是默认情况下您将获得的,这意味着您无需执行任何特殊操作即可访问 UI对象。

希望此时您不想使用 Task.Run在你的例子中。


但是您的长时间运行的任务可能是真正的异步 I/O 操作和一些 CPU 密集型操作的组合,您仍然不希望它们占用 UI 线程。此时,您通常应该考虑使用 ConfigureAwait(false)在您的等待对象上。但是您可能也希望使用 Task.Run在这里。

无论哪种情况,如果您想再次与 UI 对象交互,您都必须 Invoke回到 UI 线程。确保以正确的“粒度”执行此操作。不要Invoke 5 或 6 个单独的 UI 对象属性基本设置。但也不要 Invoke实际执行 CPU 密集型操作之前返回到 UI 线程 - 这就是您首先尝试将它们移动到不同线程的原因!

关于c# - 何时使用 Task.Run 而不是,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51398671/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com