ستاسو لخوا جوړ شوي تارونه، د دریمې ډلې ټولې برخې، او د .NET حوض د بصری سټوډیو په کړکۍ کې لیدل کیدی شي. دا کړکۍ به یوازې د تار معلومات ښکاره کړي کله چې غوښتنلیک د ډیبګ او بریک حالت کې وي. دلته تاسو کولی شئ په اسانۍ سره د هرې تار نومونه او لومړیتوبونه وګورئ، او یو ځانګړي تار ته د ډیبګ کولو بدل کړئ. د موضوع ټولګي د لومړیتوب ملکیت په کارولو سره ، تاسو کولی شئ د تار لومړیتوب وټاکئ ، کوم چې OC او CLR به د سپارښتنې په توګه درک کړي کله چې د تارونو ترمینځ د پروسیسر وخت ویشل کیږي.
کار موازي کتابتون
ټاسک موازي کتابتون (TPL) په .NET 4.0 کې معرفي شو. اوس دا د اسینکروني سره کار کولو لپاره معیاري او اصلي وسیله ده. هر هغه کوډ چې پخوانۍ طریقه کاروي میراث ګڼل کیږي. د TPL بنسټیز واحد د System.Threading.Tasks نوم ځای څخه د کاري ټولګي دی. دنده د تار په اړه یو خلاصون دی. د C# ژبې د نوې نسخې سره، موږ د Tasks - async/await operators سره کار کولو لپاره په زړه پورې لاره ترلاسه کړه. دې مفاهیمو د غیر متناسب کوډ لیکلو امکان رامینځته کړی لکه څنګه چې دا ساده او همغږي وي ، دې کار حتی د هغو خلکو لپاره هم ممکن کړی چې د تارونو داخلي کارونو لږ پوهه لري هغه غوښتنلیکونه ولیکي چې دوی یې کاروي ، هغه غوښتنلیکونه چې د اوږدې عملیاتو ترسره کولو پرمهال کنګل نه کیږي. د async/await کارول د یوې یا حتی څو مقالو لپاره یوه موضوع ده، مګر زه به هڅه وکړم چې په څو جملو کې د هغې لنډیز ترلاسه کړم:
async د ټاسک یا باطل بیرته راستنیدو میتود بدلونکی دی
او انتظار یو نه بلاکیدونکي کاري انتظار چلونکی دی.
یوځل بیا: د انتظار چلونکی ، په عمومي حالت کې (استثنا شتون لري) به د اجرا کولو اوسنی تار نور هم خوشې کړي ، او کله چې ټاسک خپل اجرا پای ته ورسوي ، او تار (په حقیقت کې ، دا به ډیر سم وي چې شرایط ووایاست. ، مګر په دې اړه نور وروسته) به د میتود اجرا کولو ته دوام ورکړي. د .NET دننه، دا میکانیزم د حاصلاتو بیرته ستنیدو په څیر پلي کیږي، کله چې لیکل شوي میتود په ټول ټولګي بدل شي، کوم چې یو دولتي ماشین دی او د دې ریاستونو پورې اړه لري په جلا جلا برخو کې اجرا کیدی شي. هرڅوک چې علاقه لري کولی شي د asynс/await په کارولو سره کوم ساده کوډ ولیکي ، د JetBrains dotPeek په کارولو سره د کمپیلر تولید شوي کوډ فعال شوي سره مجلس تالیف او وګوري.
راځئ چې د ټاسک پیل کولو او کارولو لپاره اختیارونه وګورو. د لاندې کوډ مثال کې، موږ یو نوی کار رامینځته کوو چې هیڅ ګټور نه کوي (موضوع. خوب (10000)) ، مګر په ریښتیني ژوند کې دا باید یو څه پیچلي CPU - ژور کار وي.
using TCO = System.Threading.Tasks.TaskCreationOptions;
public static async void VoidAsyncMethod() {
var cancellationSource = new CancellationTokenSource();
await Task.Factory.StartNew(
// Code of action will be executed on other context
() => Thread.Sleep(10000),
cancellationSource.Token,
TCO.LongRunning | TCO.AttachedToParent | TCO.PreferFairness,
scheduler
);
// Code after await will be executed on captured context
}
یوه دنده د یو شمیر اختیارونو سره رامینځته کیږي:
LongRunning یو اشاره ده چې دا کار به په چټکۍ سره بشپړ نشي، پدې معنی چې دا به په پام کې ونیول شي چې د حوض څخه تار نه اخلي، مګر د دې دندې لپاره یو جلا جوړ کړئ ترڅو نورو ته زیان ونه رسوي.
AttachedToParent - دندې په درجه بندي کې تنظیم کیدی شي. که دا اختیار کارول شوی وي، نو دا کار ممکن په داسې حالت کې وي چې پخپله یې بشپړ کړی وي او د خپلو ماشومانو د اعدام په تمه وي.
PreferFairness - پدې معنی چې دا به غوره وي چې د اجرا کولو لپاره لیږل شوي دندې مخکې له دې چې وروسته لیږل شوي اجرا کړئ. مګر دا یوازې یو وړاندیز دی او پایلې یې تضمین ندي.
public static async void AnotherMethod() {
int result = await AsyncMethod(); // good
result = AsyncMethod().Result; // bad
AsyncMethod().Wait(); // bad
IEnumerable<Task> tasks = new Task[] {
AsyncMethod(), OtherAsyncMethod()
};
await Task.WhenAll(tasks); // good
await Task.WhenAny(tasks); // good
Task.WaitAll(tasks.ToArray()); // bad
}
دا یوازې یو مثال دی او تاسو احتمال نه لرئ چې دا د جوړ شوي ډولونو سره ترسره کړئ ، مګر کومه پخوانۍ پروژه په ساده ډول د BeginDoSomething میتودونو سره یوځای کیږي چې د IAsyncResult او EndDoSomething میتودونه بیرته راګرځوي چې دا ترلاسه کوي.
د TaskCompletionSource ټولګي په کارولو سره د میراث API Task Based ته واړوئ
د غور کولو لپاره بله مهمه وسیله ټولګي ده د کار بشپړولو سرچینه. د دندو ، هدف او د عملیاتو اصولو په شرایطو کې ، دا ممکن یو څه د ThreadPool ټولګي RegisterWaitForSingleObject میتود یادونه وکړي ، کوم چې ما پورته په اړه لیکلي. د دې ټولګي په کارولو سره، تاسو کولی شئ په اسانۍ او په اسانۍ سره په کارونو کې زاړه غیر مطابقت لرونکي API وتړئ.
تاسو به ووایاست چې ما دمخه د دې موخو لپاره د ټاسک فاکتوري ټولګي د FromAsync میتود په اړه خبرې کړې دي. دلته به موږ په .net کې د اسینکرونوس ماډلونو د پراختیا ټول تاریخ په یاد ولرو چې مایکروسافټ په تیرو 15 کلونو کې وړاندیز کړی: د ټاسک پراساس اسینکرونوس نمونه (TAP) دمخه ، د اسینکرونوس برنامه کولو نمونه (APP) شتون درلود. د میتودونو په اړه وو پيل كيدل؛ شروع كيدل: او چنېدل، راوتلیو څه بیرته راګرځي IAsyncResult او میتودونه پايانDoSomething چې دا مني او د دې کلونو میراث لپاره د FromAsync میتود یوازې بشپړ دی ، مګر د وخت په تیریدو سره ، دا د پیښې پراساس اسینکرونوس نمونې لخوا بدل شوی (او AP)، کوم چې انګیرل چې یوه پیښه به راپورته شي کله چې د غیر متمرکز عملیات بشپړ شي.
د TaskCompletionSource د پیښې ماډل په شاوخوا کې جوړ شوي د Tasks او میراث APIs لپاس کولو لپاره مناسب دی. د دې کار جوهر په لاندې ډول دی: د دې ټولګي یو څیز د ټاسک ډول عامه ملکیت لري ، کوم حالت چې د SetResult ، SetException او داسې نورو میتودونو له لارې د TaskCompletionSource ټولګي کنټرول کیدی شي. په هغه ځایونو کې چیرې چې د انتظار چلونکی په دې ټاسک کې پلي شوی و ، دا به په استثنا سره اجرا شي یا ناکام شي د TaskCompletionSource کې پلي شوي میتود پورې اړه لري. که دا لاهم روښانه نه وي ، راځئ چې د دې کوډ مثال وګورو ، چیرې چې ځینې زاړه EAP API د TaskCompletionSource په کارولو سره په ټاسک کې پوښل شوي: کله چې پیښه اوریږي ، ټاسک به په بشپړ شوي حالت کې ځای په ځای شي ، او هغه میتود چې د انتظار آپریټر پلي کوي دې کار ته به د اعتراض ترلاسه کولو سره خپل اجرا کول بیا پیل کړي پایله.
public static Task<Result> DoAsync(this SomeApiInstance someApiObj) {
var completionSource = new TaskCompletionSource<Result>();
someApiObj.Done +=
result => completionSource.SetResult(result);
someApiObj.Do();
result completionSource.Task;
}
مګر دا ډول حل به ډیر ژر وژونکي ثابت شي ځکه چې د پیښې په تمه د پیرودونکو شمیر ډیریږي ، ځکه چې ... هر دا ډول پیرودونکی د پیښې په انتظار کې ټوله تار نیسي. هو، او موږ د 1ms اضافي ځنډ ترلاسه کوو کله چې پیښه پیل شي، ډیری وختونه دا د پام وړ نه وي، مګر ولې سافټویر د دې څخه خراب شي؟ که موږ Thread.Sleep(1) لیرې کړو، نو بیا به موږ یو پروسیسر کور 100٪ بې کاره بار کړو، په بې کاره دوره کې څرخي. د TaskCompletionSource په کارولو سره تاسو کولی شئ په اسانۍ سره دا کوډ بیا جوړ کړئ او ټولې هغه ستونزې حل کړئ چې پورته پیژندل شوي:
class LongPollingApi {
private Dictionary<int, TaskCompletionSource<Msg>> tasks;
public async Task<Msg> AcceptMessageAsync(int userId, int duration) {
var cs = new TaskCompletionSource<Msg>();
tasks[userId] = cs;
await Task.WhenAny(Task.Delay(duration), cs.Task);
return cs.Task.IsCompleted ? cs.Task.Result : null;
}
public void SendMessage(int userId, Msg m) {
if (tasks.TryGetValue(userId, out var completionSource))
completionSource.SetResult(m);
}
}
دا کوډ د تولید لپاره چمتو ندی، مګر یوازې یو ډیمو. په ریښتیني قضیو کې د دې کارولو لپاره ، تاسو اړتیا لرئ لږترلږه د وضعیت اداره کولو لپاره کله چې یو پیغام په داسې وخت کې راشي کله چې هیڅوک یې تمه نه کوي: پدې حالت کې ، د AsseptMessageAsync میتود باید دمخه بشپړ شوی دنده بیرته راستانه کړي. که دا خورا عام قضیه وي، نو تاسو کولی شئ د ValueTask کارولو په اړه فکر وکړئ.
د async/await آپریټرونه لکه د حاصل بیرته راستنیدونکي آپریټر، د میتود څخه یو دولتي ماشین رامینځته کوي، او دا د نوي څیز رامینځته کول دي، کوم چې تقریبا تل مهم نه وي، مګر په نادره مواردو کې دا ستونزه رامینځته کولی شي. دا قضیه ممکن یو میتود وي چې واقعیا ډیری وختونه ویل کیږي ، موږ په هره ثانیه کې د لسګونو او سلګونو زرو تلیفونونو په اړه خبرې کوو. که دا ډول میتود په داسې ډول لیکل شوی وي چې په ډیری حاالتو کې دا د انتظار ټولو میتودونو په تیریدو سره پایله بیرته راوړي ، نو .NET د دې مطلوب کولو لپاره وسیله چمتو کوي - د ValueTask جوړښت. د دې روښانه کولو لپاره ، راځئ چې د دې کارولو مثال وګورو: دلته یو زیرمه شتون لري چې موږ ډیری وختونه ځو. پدې کې ځینې ارزښتونه شتون لري او بیا موږ په ساده ډول دوی بیرته راګرځوو؛ که نه، نو موږ د دوی د ترلاسه کولو لپاره ځینې سست IO ته ځو. زه غواړم وروستی په غیر متناسب ډول ترسره کړم، پدې معنی چې ټوله طریقه غیر متناسب وي. په دې توګه، د میتود لیکلو روښانه لاره په لاندې ډول ده:
public async Task<string> GetById(int id) {
if (cache.TryGetValue(id, out string val))
return val;
return await RequestById(id);
}
د یو څه اصلاح کولو لیوالتیا له امله ، او د دې کوډ تالیف کولو پر مهال د روسلین څه شی رامینځته کولو لږ ویره ، تاسو کولی شئ دا مثال په لاندې ډول بیا ولیکئ:
public Task<string> GetById(int id) {
if (cache.TryGetValue(id, out string val))
return Task.FromResult(val);
return RequestById(id);
}
په حقیقت کې ، پدې قضیه کې غوره حل به د ګرمې لارې اصلاح کول وي ، د بیلګې په توګه ، پرته له کوم غیر ضروري تخصیص او په GC باندې بار کولو له لغت څخه ارزښت ترلاسه کول ، پداسې حال کې چې په نادره قضیو کې کله چې موږ لاهم اړتیا لرو د معلوماتو لپاره IO ته لاړ شو. ، هر څه به یو جمع / منفي په زاړه ډول پاتې شي:
public ValueTask<string> GetById(int id) {
if (cache.TryGetValue(id, out string val))
return new ValueTask<string>(val);
return new ValueTask<string>(RequestById(id));
}
راځئ چې د دې کوډ برخې ته نږدې وګورو: که چیرې په زیرمه کې ارزښت شتون ولري، موږ یو جوړښت رامینځته کوو، که نه نو اصلي دنده به په معنی کې پوښل شي. د زنګ وهلو کوډ پروا نه کوي چې دا کوډ په کومه لاره کې اجرا شوی و: ValueTask، د C# نحو له نظره، په دې قضیه کې به د عادي دندې په څیر چلند وکړي.
د کاري مهال ویش: د کار پیل کولو ستراتیژیو اداره کول
په .NET کې د تارونو سره کار کول د Thread او ThreadPool ټولګیو لخوا نمایش کیږي
د Thread.Abort، Thread.Interrupt، او Win32 API TerminateThread میتودونه خطرناک دي او د کارولو لپاره وړاندیز نه کیږي. پرځای یې، دا غوره ده چې د CancellationToken میکانیزم وکاروئ
جریان یوه ارزښتناکه سرچینه ده او عرضه یې محدوده ده. هغه حالتونه چیرې چې تارونه د پیښو په انتظار کې بوخت وي باید مخنیوی وشي. د دې لپاره دا د TaskCompletionSource ټولګي کارول اسانه دي
د موازي او غیر مطابقت سره د کار کولو لپاره خورا پیاوړي او پرمختللي .NET وسیلې دندې دي.
د c# async/await آپریټرونه د غیر بندیدو انتظار مفهوم پلي کوي