在C#中,Task和async/await是处理异步操作的强大工具。然而,在某些情况下,我们可能需要更细粒度地控制任务的完成状态,而不是简单地等待它完成。这时,TaskCompletionSource<T>就派上了用场。TaskCompletionSource<T>允许我们手动地设置任务的结果、异常或取消状态,从而提供了对任务执行的更高级别控制。本文将介绍TaskCompletionSource<T>的基本用法,并通过一个WinForms示例展示如何使用它来控制任务结果。
TaskCompletionSource<T>是一个非常有用的类,它允许创建一个没有绑定到某个特定操作的Task<T>。这意味着你可以手动控制这个Task<T>的完成时机和结果。这在你需要将基于事件的异步模式与基于任务的异步模式进行桥接时非常有用。
在软件开发中,由于网络波动、服务暂时不可用或其他临时问题,外部服务调用可能会失败。为了增强系统的健壮性,通常会实现重试模式(Retry Pattern),尝试重新执行失败的操作。本文将介绍如何在C#中使用异步编程实现重试模式,并提供一个完整的WinForms示例。
重试模式指的是在操作失败后,自动重新尝试执行该操作的过程,通常会伴随一定的延迟(退避策略)和最大尝试次数限制。这种模式有助于处理暂时性故障,而不是立即向用户报告错误。
在C#中,可以通过异步编程结合Task和await关键字来实现重试逻辑。以下是一个简单的异步重试方法的示例:
C#using System;
using System.Threading.Tasks;
public static class RetryHelper
{
public static async Task<T> RetryOnExceptionAsync<T>(int maxAttempts, TimeSpan delay, Func<Task<T>> operation)
{
var attempts = 0;
do
{
try
{
attempts++;
return await operation();
}
catch (Exception)
{
if (attempts == maxAttempts)
throw;
await Task.Delay(delay);
}
} while (true);
}
}
在C#中,线程优先级是指操作系统调度线程执行的顺序。每个线程都有一个优先级,这决定了它与其他线程相比获取CPU时间的优先权。C#利用System.Threading.ThreadPriority枚举来设置线程的优先级。
ThreadPriority枚举包含以下值:
Lowest:最低优先级。BelowNormal:低于正常优先级。Normal:正常优先级。AboveNormal:高于正常优先级。Highest:最高优先级。下面的示例演示了如何创建两个线程,并为它们设置不同的优先级。
C#using System;
using System.Threading;
class Program
{
static void Main()
{
Thread thread1 = new Thread(Thread1Function);
Thread thread2 = new Thread(Thread2Function);
// 设置线程优先级
thread1.Priority = ThreadPriority.Lowest;
thread2.Priority = ThreadPriority.Highest;
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine("主线程结束。");
}
static void Thread1Function()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Thread1正在执行...");
Thread.Sleep(1000);
}
}
static void Thread2Function()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Thread2正在执行...");
Thread.Sleep(1000);
}
}
}
在.NET中,AutoResetEvent和ManualResetEvent是两种常用的同步原语,它们用于在多线程环境中实现线程之间的同步。尽管它们都是从EventWaitHandle派生的,但它们在行为上有所不同。在Windows窗体(WinForms)应用程序中,这两种事件可以帮助我们在UI线程和工作线程之间同步操作,以确保线程安全和数据的一致性。
AutoResetEvent是一个同步原语,当它被设置为信号状态时,允许一个等待的线程继续执行。一旦释放了一个等待的线程,AutoResetEvent会自动回到非信号状态,这意味着它会自动重置。
假设我们在WinForms应用程序中有一个需要执行长时间运行操作的按钮。我们可以使用AutoResetEvent来确保在操作完成之前,用户不能再次点击该按钮。
C#private AutoResetEvent autoResetEvent = new AutoResetEvent(true);
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
if (autoResetEvent.WaitOne(0))
{
Task.Run(() =>
{
// 执行长时间运行的操作
Thread.Sleep(5000); // 假设操作耗时5秒
this.Invoke(() =>
{
lblTitle.Text = DateTime.Now.ToString();
});
// 操作完成,设置事件状态,允许再次点击按钮
autoResetEvent.Set();
});
}
else
{
MessageBox.Show("操作正在进行中,请稍候...");
}
}
在 C# 中,CancellationTokenSource 是一个用于创建和管理 CancellationToken(取消标记)的类。它提供了一种简单的方式来请求取消异步或多线程操作。
看一下Cancel的顺序
C#static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken cancellationToken = cts.Token;
cancellationToken.Register(() =>
{
Console.WriteLine("Cancel1...");
});
cancellationToken.Register(() =>
{
Console.WriteLine("Cancel2...");
});
cancellationToken.Register(state =>
{
Console.WriteLine("Cancel3..." + state.ToString());
}, "OK");
Console.WriteLine("开始...");
cts.Cancel();
}