अब तक मैंने थ्रेडिंग टाइमर के बजाय चक्रीय सीपीयू बाउंड बैकग्राउंड कार्य के लिए एक LongRunning TPL कार्य का उपयोग किया, क्योंकि:
- TPL कार्य रद्द करने का समर्थन करता है
- थ्रेडिंग टाइमर एक और थ्रेड शुरू कर सकता है, जबकि प्रोग्राम बंद हो रहा है जिससे डिस्पोजल संसाधनों के साथ संभावित समस्याएं हो सकती हैं
- ओवररन के लिए मौका: थ्रेडिंग टाइमर एक और धागा शुरू कर सकता है जबकि पिछले अभी भी अप्रत्याशित लंबे काम के कारण संसाधित हो रहा है (मुझे पता है, इसे रोकने और टाइमर को पुनरारंभ करने से रोका जा सकता है)
हालांकि, टीपीएल समाधान हमेशा एक समर्पित धागे का दावा करता है जो कि अगली कार्रवाई (जो कि ज्यादातर समय होता है) की प्रतीक्षा करते समय आवश्यक नहीं है। मैं पृष्ठभूमि पर सीपीयू बाध्य चक्रीय कार्य करने के लिए जेफ के प्रस्तावित समाधान का उपयोग करना चाहूंगा क्योंकि इसे केवल एक थ्रेडपूल धागा की आवश्यकता होती है जब ऐसा करने के लिए काम होता है जो स्केलेबिलिटी के लिए बेहतर होता है (विशेषकर जब अंतराल अवधि बड़ी होती है)।
इसे प्राप्त करने के लिए, मैं 4 अनुकूलन सुझाऊंगा:
- थ्रेड पूल थ्रेड पर कार्रवाई निष्पादित
ConfigureAwait(false)
करने के Task.Delay()
लिए जोड़ें doWork
, अन्यथा doWork
कॉलिंग थ्रेड पर प्रदर्शन किया जाएगा जो समानता का विचार नहीं है
- एक TaskCanceledException (अभी भी आवश्यक है?) फेंकने से रद्द करने के पैटर्न से चिपके रहते हैं।
- रद्दीकरण को आगे ले
doWork
जाएं ताकि कार्य को रद्द करने में सक्षम किया जा सके
- टास्क स्टेट जानकारी (जैसे TPL कार्य) की आपूर्ति करने के लिए टाइप ऑब्जेक्ट का एक पैरामीटर जोड़ें
बिंदु 2 के बारे में मुझे यकीन नहीं है, क्या async इंतजार अभी भी TaskCanceledExecption की आवश्यकता है या यह सिर्फ सबसे अच्छा अभ्यास है?
public static async Task Run(Action<object, CancellationToken> doWork, object taskState, TimeSpan period, CancellationToken cancellationToken)
{
do
{
await Task.Delay(period, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
doWork(taskState, cancellationToken);
}
while (true);
}
कृपया प्रस्तावित समाधान के लिए अपनी टिप्पणी दें ...
अपडेट 2016-8-30
उपरोक्त समाधान तुरंत कॉल नहीं करता है doWork()
लेकिन await Task.Delay().ConfigureAwait(false)
थ्रेड स्विच को प्राप्त करने के लिए शुरू होता है doWork()
। नीचे दिए गए समाधान में पहली doWork()
कॉल लपेटकर इस समस्या पर काबू पा लिया गया हैTask.Run()
और उसका इंतजार किया गया।
नीचे सुधार के लिए async \ प्रतीक्षा प्रतिस्थापन है Threading.Timer
जो कि रद्द करने योग्य चक्रीय कार्य करता है और स्केलेबल (TPL समाधान की तुलना में) करता है क्योंकि यह अगली कार्रवाई की प्रतीक्षा करते समय किसी भी थ्रेड पर कब्जा नहीं करता है।
ध्यान दें कि टाइमर के विपरीत, प्रतीक्षा समय ( period
) स्थिर है और चक्र समय नहीं है; चक्र समय प्रतीक्षा समय का योग है और जिसकी अवधि doWork()
अलग-अलग हो सकती है।
public static async Task Run(Action<object, CancellationToken> doWork, object taskState, TimeSpan period, CancellationToken cancellationToken)
{
await Task.Run(() => doWork(taskState, cancellationToken), cancellationToken).ConfigureAwait(false);
do
{
await Task.Delay(period, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
doWork(taskState, cancellationToken);
}
while (true);
}