This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Friday, 12 December 2025
أكثر أنظمة الـ إلى تذكّر أكثر من اللازم (اللوحات، الطوابير، الخردة المستمرة التي لا تريدها أبداً) أو أنها لا تتذكر شيئاً على الإطلاق (الثقوب السوداء المشتعلة والنسيان التي تختفي لحظة حدوث خطأ ما).
تُدخل هذه المادة شيئاً مختلفاً:
A نمط حيث تصبح كل عملية Async عملية صغيرة طراز SALL, المعاينة, إعادة صلاح إعادة صلاح, وحدة العمل الخاصة للتنظيف الذاتي -والنظام بأكمله يبقى خاصّاً، مربوطاً، سريع، وحاسماً
إنها مرافقة مقالتي السابقة **تعلّم LRUs - عندما تتخطى القدرة تجعل نظامك افضل**الذي واحد إستكشفَ كَمْ الذاكرة المُحَدّدة + إنتهاء يُصبحُ a آلية بقاء.
هذا يستكشف النصف الآخر: التنفيذ الانجازي والاعدام - كيف أن عازلاً متدحرجاً صغيراً من المهام النشطة يصبح مصححاً، سجل حدث، ومحرك إعادة تشغيل، دون الاحتفاظ بأي بيانات مستخدم.
هذا المثال يأتي من ترجمة مدونتي UI - وهي عبارة عن مجموعة صغيرة لترجمة محتوى العلامة التنازلية على الجو. تبدو تافهة. تحت غطاء محرك السيارة، تنفذ أنماطاً يمكنك سرقتها من أجل أي سير عمل متأرجح.
هذا الجزء الأول من سلسلة من جزأين:
هذا هو الآن في معظم الغالب liflucyd.ephimmerals Nuget حزمة أيضا أكثر من 20.
ويميل مطورو الشبكة إلى الاختيار من ثلاثة خيارات سيئة:
Task.Run() لا علاقة، لا إعادة بناء، لا فكرة عمّا فشل.أنت تحجب الخيوط التي لا يجب أن تحجبها.
الآن لديك:
مفيد لكن خارجي أيضاً لا يمكنه إعادة أي شيء و كثيراً ما يسرب البيانات التي لم تنوي تخزينها
ما نريده في الواقع هو:
ذاكرة "فقط طويلة بما فيه الكفاية" لما يفعله النظام - ولا شيء أكثر من ذلك.
هذه هي الفكرة في جملة واحدة:
ابدأ عملية Ayync فوراً، تعقبها بشكل صريح من خلال مهمّة مكمّلة Source، تنظيفها بشكل تحديدي، والحفاظ على عازل متدحرج صغير للمهمّات القليلة الأخيرة حتى تتمكن من فحصها أو استعادتها - دون الاحتفاظ بأي محتوى مستخدم.
يقع في منتصف الطريق بين:
من دون أن يصبح أي منهم
flowchart TB
subgraph Client["Client Request"]
R[Start Translation]
end
subgraph API["API Layer"]
A[Create TaskId] --> B[Create TaskCompletionSource]
B --> C[Queue to Channel]
C --> D[Return TaskId Immediately]
end
subgraph Cache["Ephemeral Cache (Bounded)"]
E[Store TranslateTask]
F[Max 5 per user]
G[6hr absolute / 1hr sliding expiry]
end
subgraph Worker["Background Worker"]
H[Read from Channel]
H --> I[Execute Translation]
I --> J[Complete TCS]
end
R --> A
B --> E
E --> F --> G
C --> H
style Cache fill:none,stroke:#10b981,stroke-width:2px
style Worker fill:none,stroke:#6366f1,stroke-width:2px
هيكل البيانات الأساسية هو: TranslateTask - وحدة تنفيذ ذرية صغيرة جداً يدعمها Task<TaskCompletion>:
// From TranslateTask.cs
public class TranslateTask(
string taskId,
DateTime startTime,
string language,
Task<TaskCompletion>? task)
: TranslateResultTask(taskId, startTime, language)
{
public Task<TaskCompletion>? Task { get; init; } = task;
}
public record TaskCompletion(
string? TranslatedMarkdown,
string OriginalMarkdown,
string Language,
bool Complete,
DateTime? EndTime);
وهي تحتوي على ما يلي:
Task<TaskCompletion>هذا كل شيء، لا شيء مستمر، لا شيء مكتوب على القرص، لا شيء مخزّن خلف النافذة المتداولة.
AWS لديها وظائف متدرجة. الأزور له وظائف دائمة. لديك... 30 سطر من الرموز التي لا تتطلب فاتورة سحابة.
والسحر الذي يحدث في BackgroundTranslateServiceبدلاً من النار والنسيان، نستخدم المهمة المُمَلْس المصدر - بناء مثل الوعد الذي يسمح لنا بالعودة على الفور بينما العمل يحدث في الخلفية.
// From BackgroundTranslateService.cs
private readonly Channel<(PageTranslationModel, TaskCompletionSource<TaskCompletion>)>
_translations = Channel.CreateUnbounded<(PageTranslationModel, TaskCompletionSource<TaskCompletion>)>();
private async Task<Task<TaskCompletion>> Translate(PageTranslationModel message)
{
// Create a TaskCompletionSource that will eventually hold the result
var tcs = new TaskCompletionSource<TaskCompletion>();
// Send the translation request along with the TCS to be processed
await _translations.Writer.WriteAsync((message, tcs));
// Return the Task immediately -caller can await it or check status later
return tcs.Task;
}
إذا لم تستخدم TaskCompletionSource<T> النظر إليها على أنها وعداً بأنّك تتحكّم يدوياًعلى سبيل المثال منظّم Task الذي يكمّل عندما ينتهي عمله، يكمّل TCS متى - - - - - - - - - - - نداء مُتّ اتصل SetResult(), SetException()أو SetCanceled().
هذا يسمح لك:
Task إلى المُتَّصل فوراًإنه الجسر بين "النيران والنسيان" و "النيران والمسار"
عندما ينقر مستخدم على "تفضّل"، فإن الواجهة الأمامية تدعو API:
// From translations.js
fetch('/api/translate/start-translation', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
Language: shortCode,
OriginalMarkdown: markdown
})
})
.then(response => response.json())
.then(taskId => {
// Got a taskId immediately -translation is running in background
console.log("Task ID:", taskId);
// Poll for updates via HTMX
htmx.ajax('get', "/editor/get-translations", {
target: '#translations',
swap: 'innerHTML'
});
});
الدالة API ترجع فوراً مع فقط a مهمّة تعريف:
// From TranslateAPI.cs
[HttpPost("start-translation")]
public async Task<Results<Ok<string>, BadRequest<string>>> StartTranslation(
[FromBody] MarkdownTranslationModel model)
{
if (!backgroundTranslateService.TranslationServiceUp)
return TypedResults.BadRequest("Translation service is down");
// Create a unique identifier for this translation task
var taskId = Guid.NewGuid().ToString("N");
var userId = Request.GetUserId(Response);
// Trigger translation -returns Task<TaskCompletion> immediately
var translationTask = await backgroundTranslateService.Translate(model);
// Wrap it in our trackable TranslateTask
var translateTask = new TranslateTask(taskId, DateTime.Now, model.Language, translationTask);
// Store in the ephemeral cache (bounded, self-cleaning)
translateCacheService.AddTask(userId, translateTask);
// Return the task ID to the client -they can poll for status
return TypedResults.Ok(taskId);
}
الإستجابة فورية. الترجمة الفعلية تعمل في الخلفية. المستخدم يمكن أن يستطلع أو يشاهد فقط تحديث UI.
ثانياً - التبصيـرة الرئيسيـة مـن أولاً - المادة من الاتحاد الروسي ينطبق هنا أيضاً:
الاحتفاظ بما يكفي من التاريخ لإزالة الحشرة والعقل حول النظام... وترك التحلل الطبيعي يمحو كل شيء آخر.
// From TranslateCacheService.cs
public class TranslateCacheService(IMemoryCache memoryCache)
{
public void AddTask(string userId, TranslateTask task)
{
if (memoryCache.TryGetValue(userId, out CachedTasks? tasks))
{
var currentTasks = tasks?.Tasks ?? new List<TranslateTask>();
currentTasks = currentTasks.OrderByDescending(x => x.StartTime).ToList();
// Keep only the 5 most recent tasks -bounded window
if (currentTasks.Count >= 5)
{
var lastTask = currentTasks.Last();
currentTasks.Remove(lastTask);
}
currentTasks.Add(task);
currentTasks = currentTasks.OrderByDescending(x => x.StartTime).ToList();
tasks!.Tasks = currentTasks;
memoryCache.Set(userId, tasks, new MemoryCacheEntryOptions
{
AbsoluteExpiration = tasks.AbsoluteExpiration,
SlidingExpiration = TimeSpan.FromHours(1)
});
}
else
{
// First task for this user
var cachedTasks = new CachedTasks
{
Tasks = new List<TranslateTask> { task },
AbsoluteExpiration = DateTime.Now.AddHours(6)
};
memoryCache.Set(userId, cachedTasks, new MemoryCacheEntryOptions
{
AbsoluteExpiration = cachedTasks.AbsoluteExpiration,
SlidingExpiration = TimeSpan.FromHours(1)
});
}
}
public List<TranslateTask> GetTasks(string userId)
{
if (memoryCache.TryGetValue(userId, out CachedTasks? tasks))
return tasks?.Tasks ?? new List<TranslateTask>();
return new List<TranslateTask>();
}
private class CachedTasks
{
public List<TranslateTask> Tasks { get; set; } = new();
public DateTime AbsoluteExpiration { get; set; }
}
}
كل مهمة جديدة:
flowchart LR
subgraph Window["Per-User Task Window (Max 5)"]
T1[Oldest Task] --- T2[Older] --- T3[Recent] --- T4[Newer] --- T5[Newest]
end
New[New Task] -->|Enqueue| Window
T1 -->|Evicted| Gone[(Expired)]
style Window fill:none,stroke:#10b981,stroke-width:2px
style Gone fill:none,stroke:#ef4444,stroke-width:2px
لا توجد مخاطرة تتعلق بالاحتجاز. لا يوجد PCI في الخزينة (فقط هويات المهام، وازمنات الطوابع، ورموز اللغات). لا يوجد صداع في الناتج المحلي الإجمالي.
تُنفِّذ خدمة المعلومات الأساسية **** الحلقة التي تستخدم قار قارة وق Task.WhenAny:
// From BackgroundTranslateService.cs
private async Task TranslateFilesAsync(CancellationToken cancellationToken)
{
var processingTasks = new List<Task>();
while (!cancellationToken.IsCancellationRequested)
{
// Fill up to IPCount concurrent tasks (e.g., 4 parallel translations)
while (processingTasks.Count < markdownTranslatorService.IPCount &&
!cancellationToken.IsCancellationRequested)
{
var item = await _translations.Reader.ReadAsync(cancellationToken);
var translateModel = item.Item1;
var tcs = item.Item2;
// Start the task and add it to the list
var task = TranslateTask(cancellationToken, translateModel, item, tcs);
processingTasks.Add(task);
}
// Wait for ANY of the tasks to complete
var completedTask = await Task.WhenAny(processingTasks);
processingTasks.Remove(completedTask);
// Handle exceptions if needed
try
{
await completedTask;
}
catch (Exception ex)
{
logger.LogError(ex, "Error translating markdown");
}
}
}
هذا هو مثل a الحاكم الحاكم على المحرك البخاري: المزيد من الحمل / الضغط الخلفي يبني o constructing o construction o consulting o constable.
النمط يعطيك:
عندما تنتهي عملية الترجمة الفعلية نكمل العملية
// From BackgroundTranslateService.cs
private async Task TranslateTask(
CancellationToken cancellationToken,
PageTranslationModel translateModel,
(PageTranslationModel, TaskCompletionSource<TaskCompletion>) item,
TaskCompletionSource<TaskCompletion> tcs)
{
try
{
await retryPolicy.ExecuteAsync(async () =>
{
// Do the actual translation work
var translatedMarkdown = await markdownTranslatorService.TranslateMarkdown(
translateModel.OriginalMarkdown,
translateModel.Language,
cancellationToken);
// SUCCESS: Complete the TCS with the result
tcs.SetResult(new TaskCompletion(
translatedMarkdown,
translateModel.OriginalMarkdown,
translateModel.Language,
true,
DateTime.Now));
});
}
catch (TranslateException e)
{
// FAILURE: Complete the TCS with an exception
tcs.SetException(new Exception($"Translation failed after 3 retries: {e.Message}"));
}
catch (Exception e)
{
// UNEXPECTED: Complete the TCS with the exception
tcs.SetException(e);
}
}
المتصل Task<TaskCompletion> -والتي حصلوا عليها فوراً عندما اتصلوا Translate() -اكتملت الآن، يمكنهم:
await إذا كانوا يريدون أن مربعIsCompleted إلىIsFaulted لنرى إن كانت قد فشلتResult إلى تحصل على المحتوى المترجمعند عرض المهام إلى المستخدم، نقوم بإسقاط حالة المهمة الحية إلى نموذج عرضي:
// From TranslateTask.cs
public TranslateResultTask(TranslateTask task, bool includeMarkdown = false)
{
TaskId = task.TaskId;
StartTime = task.StartTime;
Language = task.Language;
// Check for faulted state first -a faulted task is also "completed" in .NET terms
if (task.Task?.IsFaulted == true)
{
Failed = true;
Completed = false;
TotalMilliseconds = (int)(DateTime.Now - task.StartTime).TotalMilliseconds;
}
else if (task.Task?.IsCompletedSuccessfully == true)
{
Completed = true;
Failed = false;
var endTime = task.Task.Result.EndTime;
TotalMilliseconds = (int)((endTime - task.StartTime)!).Value.TotalMilliseconds;
EndTime = endTime;
}
else
{
// Still in progress
Completed = false;
Failed = false;
TotalMilliseconds = (int)(DateTime.Now - task.StartTime).TotalMilliseconds;
}
if (Completed && includeMarkdown)
{
var result = task.Task?.Result;
if (result == null) return;
OriginalMarkdown = result.OriginalMarkdown;
TranslatedMarkdown = result.TranslatedMarkdown;
}
}
(الإنترات) Task لَهُ بَعْض تركيباتِ الحالةِ الشاذةِ:
IsCompleted حقاً لـ -لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا، لا الإنجاز الناجح والمهمات المتعثرةIsCompletedSuccessfully فقط من أجل النجاحIsFaulted يعني أنه رمى استثناءIsCanceled يعني أنه كان قد أُلغيلذا يجب عليك التحقق IsFaulted قبل قبل IsCompletedأو ستعامل الفشل على أنه نجاح
الـ اعرض لـ تحديثات استخدام HTMx s hx-trigger:
@* From _GetTranslations.cshtml *@
@{
var allCompleted = Model.All(x => x.Completed);
var trigger = allCompleted ? "none" : "every 5s";
}
<div class="translationpoller"
hx-get="/editor/get-translations"
hx-swap="outerHTML"
hx-trigger="@trigger">
<table class="table">
@foreach (var item in Model)
{
<tr>
<td>
@if (item.Completed)
{
<a href="#" x-on:click.prevent="viewTranslation('@item.TaskId')">View</a>
}
else if (item.Failed)
{
<text>Failed</text>
}
else
{
<text>Processing</text>
}
</td>
<td>
@if (item.Completed)
{
<i class='bx bx-check text-green'></i>
}
else if (item.Failed)
{
<i class='bx bx-x text-red'></i>
}
else
{
<img src="~/img/3-dots-bounce.svg" />
}
</td>
<td>@item.Language</td>
<td>@TimeSpan.FromMilliseconds(item.TotalMilliseconds).Humanize()</td>
</tr>
}
</table>
</div>
الجزء الماهر: hx-trigger="@trigger" التغييرات استناداً إلى الحالة:
"none")هذا ** تنظيم عمليات الاقتراع الذاتي** -يتوقف تلقائياً عندما لا يكون هناك شيء ليشاهده
عندما يقرض المستخدم "View"، نجلب الترجمة المكتملة:
// From TranslateAPI.cs
[HttpGet("get-translation/{taskId}")]
public async Task<Results<JsonHttpResult<TranslateResultTask>, BadRequest<string>>> GetTranslation(
string taskId)
{
var userId = Request.GetUserId(Response);
var tasks = translateCacheService.GetTasks(userId);
var translationTask = tasks.FirstOrDefault(t => t.TaskId == taskId);
if (translationTask == null)
return TypedResults.BadRequest("Task not found");
// Include the markdown content in the response
var result = new TranslateResultTask(translationTask, includeMarkdown: true);
return TypedResults.Json(result);
}
الـ جافاScript ثمّ يُمْكِنُ مُحرّر:
// From translations.js
export function viewTranslation(taskId) {
fetch(`/api/translate/get-translation/${taskId}`)
.then(response => response.json())
.then(data => {
// Show the translated content area
document.getElementById("translatedcontent").classList.remove("hidden");
// Populate the editors
var originalMde = window.mostlylucid.simplemde.getinstance('translatedcontentarea');
originalMde.value(data.originalMarkdown);
var mde = window.mostlylucid.simplemde.getinstance('markdowneditor');
mde.value(data.translatedMarkdown);
});
}
السبب:
هذا هو الهيكل أتمنى لو استخدمت المتصفحات والأطر الأمامية لعمليات الدورة.
ما تحصل عليه بدون التفكير ملياً
كيف يمكن |---------|-----| | الماه (ك) عملة مقننة عن طريق قناة + نمط السيماصور | لفرة * المزيد من الحمل * المزيد من الضغط على الظهر * سلوك ثابت * | **** العمليات الدقيقة موجودة بما يكفي لتفتيش | القابل ○ يمكن الوصول إلى النتائج المستكملة حتى تنتهي صلاحيتها | (أ) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ▪ توحد الخصوصية والبساطة لمرة واحدة | التنفيذ ♪ المهام القديمة تسقط بعيدا، المهام ذات الصلة تظل ♪
تماما مثل مخبأ LRU شحذ الذاكرة السلوكية، ونافذة التشغيل المتداولة شحذ وجهة نظر التنفيذ.
استخدمه عندما:
لا تستخدمه عندما:
في هذه الحالة: أولاً - المادة من الاتحاد الروسي كان حول التعلم بالنسيس، هذا هو هذا هو عن عن طريق التنفيذ بالتبخر.
النظام يتذكر بالضبط ما يكفي ليكون مفيداً وليس أكثر من ذلك
إنه:
أنت تعرف بالفعل كيف تنفذه: TaskCompletionSource)أ( Channel(ج) IMemoryCache مع إنتهاء الإنهيار، وعامل خلفية.
النار... ولا تنساها تماماً.
داخل **الجزء 2: بناء مكتبة تنفيذ اقتصادي يمكن إعادة استخدامها**سنحول هذا النمط إلى مساعد
EphemeralForEachAsync<T> - مثل - Parallel.ForEachAsync مع عملية التتبعEphemeralWorkCoordinator<T> - طاولة عمل طويلة الأجل يمكن ملاحظتهاAddEphemeralWorkCoordinator<TCoordinator> (تقريباً) AddHttpClient)© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.