مدیریت لغو عملیات در برنامهنویسی ناهمگام با Task.FromCanceled
نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۳/۰۶ ۰۹:۵۴
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
CancellationToken و الگوهای پایه لغو آشنا هستند، اما Task.FromCanceled ابزاری کمتر شناخته شده ولی قدرتمند است که میتواند به بهبود چشمگیر کدهای ناهمگام شما کمک کند. این مقاله به بررسی عمیق Task.FromCanceled، کاربردهای آن و بهترین روشهای استفاده از آن برای توسعهدهندگان میپردازد.Task.FromCanceledچیست؟Task.FromCanceled یک متد استاتیک (Static Method) در کتابخانه موازی وظایف (Task Parallel Library - TPL) است که به شما امکان میدهد یک شیء Task را در وضعیت لغو شده (Canceled State) ایجاد کنید. این متد به طور خاص برای سناریوهایی طراحی شده است که نیاز به ایجاد صریح یک تسک لغو شده دارید، بدون اینکه یک عملیات واقعی شروع شده و سپس لغو شود. دو نسخه از این متد وجود دارد:public static Task FromCanceled(CancellationToken cancellationToken)public static Task<TResult> FromCanceled<TResult>(CancellationToken cancellationToken)cancellationToken که به این متد پاس داده میشود، توکنی است که علت لغو را نشان میدهد.Task.FromCanceled، بررسی زودهنگام لغو قبل از شروع یک عملیات پرهزینه یا پیچیده است. این رویکرد به شما امکان میدهد از انجام کارهای غیرضروری جلوگیری کرده و منابع سیستم را آزاد کنید. به عنوان مثال، در یک متد ناهمگام، میتوانید وضعیت CancellationToken را در ابتدای کار بررسی کنید و در صورت درخواست لغو، یک تسک لغو شده را برگردانید:public async Task ProcessDataAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled(cancellationToken);
}
// ادامه با پردازش عادی
return await DoWorkAsync();
}public async Task<string> GetDataAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<string>(cancellationToken);
}
return await FetchDataAsync();
}await Task.FromCanceled(...)، کد فراخواننده (Caller) میتواند لغو را به درستی مدیریت کند و یک OperationCanceledException را دریافت نماید.Task.FromCanceled در سناریوهای مختلفی میتواند مفید باشد:public async Task<DataResult> ProcessLargeDatasetAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return await Task.FromCanceled<DataResult>(cancellationToken);
}
var data = await LoadLargeDatasetAsync();
return new DataResult(data);
}public async Task<Report> GenerateReportAsync(ReportType type, CancellationToken cancellationToken)
{
if (!IsReportTypeSupported(type))
{
return await Task.FromCanceled<Report>(cancellationToken);
}
return await GenerateReportInternalAsync(type);
}public async Task<ValidationResult> ValidateDataAsync(DataModel data, CancellationToken cancellationToken)
{
if (data == null)
{
return await Task.FromCanceled<ValidationResult>(cancellationToken);
}
return await PerformValidationAsync(data);
}Task.FromCanceled میتواند در کنار الگوهای پیچیدهتر برنامهنویسی ناهمگام نیز استفاده شود:Task.FromCanceled راهکاری مناسب است. این در بلوکهای catch برای مدیریت OperationCanceledException مفید است:public async Task<Result> ProcessWithFallbackAsync(CancellationToken cancellationToken)
{
try
{
return await PrimaryOperationAsync();
}
catch (OperationCanceledException)
{
return await Task.FromCanceled<Result>(cancellationToken);
}
catch (Exception)
{
return await FallbackOperationAsync();
}
}Task.FromCanceled را در صورت لغو CancellationToken استفاده کند. این به ایجاد کدی تمیزتر و قابل استفاده مجدد کمک میکند:public class CustomTaskFactory
{
public static async Task<T> CreateTaskAsync<T>(
Func<Task<T>> operation,
CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return await Task.FromCanceled<T>(cancellationToken);
}
try
{
return await operation();
}
catch (OperationCanceledException)
{
return await Task.FromCanceled<T>(cancellationToken);
}
}
}CancellationTokenSource و Task.FromCanceled میتوان یک الگوی تایماوت قدرتمند پیادهسازی کرد. CancellationTokenSource میتواند برای لغو خودکار پس از یک مدت زمان مشخص پیکربندی شود:public async Task<Result> ExecuteWithTimeoutAsync(
Func<Task<Result>> operation,
TimeSpan timeout)
{
using var cts = new CancellationTokenSource(timeout);
try
{
return await operation();
}
catch (OperationCanceledException)
{
return await Task.FromCanceled<Result>(cts.Token);
}
}Task.FromCanceled و اطمینان از عملکرد صحیح مدیریت لغو، رعایت بهترین روشها ضروری است:CancellationToken را ارسال کنید: همواره همان CancellationToken را که برای ایجاد تسک لغو شده استفاده شده است، به متد Task.FromCanceled ارسال کنید. ارسال یک CancellationToken جدید یا خالی، میتواند منجر به رفتار غیرمنتظره و عدم ردیابی صحیح لغو شود. این کار به سیستم لغو امکان میدهد که به درستی تشخیص دهد کدام عملیات لغو شده است.// خوب return Task.FromCanceled(cancellationToken); // بد return Task.FromCanceled(new CancellationToken());
public async Task<Result> ProcessWithMessageAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
_logger.LogInformation("Operation canceled by user");
return await Task.FromCanceled<Result>(cancellationToken);
}
return await ProcessAsync();
}Task.WhenAll: هنگام کار با چندین تسک به صورت همزمان (مثلاً با Task.WhenAll)، استفاده از Task.FromCanceled میتواند به شما کمک کند تا در صورت لغو یکی از تسکها، کل مجموعه تسکها را لغو شده اعلام کنید. این تضمین میکند که حتی اگر یک تسک لغو شود، Task.WhenAll نیز به درستی با یک OperationCanceledException تکمیل شود.public async Task<Result[]> ProcessMultipleAsync(CancellationToken cancellationToken)
{
var tasks = new List<Task<Result>>();
foreach (var item in items)
{
if (cancellationToken.IsCancellationRequested)
{
return await Task.FromCanceled<Result[]>(cancellationToken);
}
tasks.Add(ProcessItemAsync(item));
}
return await Task.WhenAll(tasks);
}Task.FromCanceled میتواند در مراحل مختلف برای مدیریت اعتبارسنجی (Validation) و لغو عملیات استفاده شود:public class DataProcessingPipeline
{
private readonly ILogger<DataProcessingPipeline> _logger;
public async Task<ProcessedData> ProcessDataAsync(
RawData data,
CancellationToken cancellationToken)
{
try
{
// اعتبارسنجی ورودی
if (!IsValid(data))
{
_logger.LogWarning("Invalid data received");
return await Task.FromCanceled<ProcessedData>(cancellationToken);
}
// پردازش داده
var result = await TransformDataAsync(data);
// اعتبارسنجی خروجی
if (!IsValid(result))
{
_logger.LogError("Invalid result generated");
return await Task.FromCanceled<ProcessedData>(cancellationToken);
}
return result;
}
catch (OperationCanceledException)
{
_logger.LogInformation("Operation canceled");
return await Task.FromCanceled<ProcessedData>(cancellationToken);
}
}
}catch، هر OperationCanceledException گرفته شده و یک تسک لغو شده مجدداً برگردانده میشود، که نشاندهنده لغو عملیات توسط سیستم یا کاربر است. این رویکرد به شما امکان میدهد تا یک مدل یکپارچه و قابل پیشبینی برای مدیریت لغو در سراسر خط لوله پردازش خود داشته باشید.Task.FromCanceled ابزاری قدرتمند و انعطافپذیر در جعبه ابزار برنامهنویسی ناهمگام در سیشارپ است. این متد راهی تمیز و صریح برای مدیریت سناریوهای لغو و ایجاد تسکهای لغو شده فراهم میکند. گرچه ممکن است در هر عملیات ناهمگام ضروری نباشد، اما درک زمان و نحوه استفاده از آن میتواند به ایجاد کدی مقاومتر، قابل نگهداریتر و با مدیریت خطای بهتر منجر شود. با استفاده صحیح از Task.FromCanceled، توسعهدهندگان میتوانند تجربه کاربری بهتری ارائه دهند، زیرا برنامهها میتوانند به درخواستهای لغو به طور مؤثر پاسخ دهند و از هدر رفتن منابع جلوگیری کنند. به خاطر داشته باشید که همیشه CancellationToken اصلی را ارسال کنید، لغو را به صورت graceful مدیریت کنید و این ابزار را در سناریوهای اعتبارسنجی و خروج زودهنگام در نظر بگیرید.