मुझे वास्तव में यह सवाल पसंद है:
C # में आग लगाने और भूलने का सरल तरीका?
मैं बस यह जानना चाहता हूं कि अब हमारे पास C # 4.0 में पैरेलल एक्सटेंशन हैं। फायर एंड फॉरगेट विथ पैरेलल लाइनक करने के लिए बेहतर क्लीनर तरीका है?
मुझे वास्तव में यह सवाल पसंद है:
C # में आग लगाने और भूलने का सरल तरीका?
मैं बस यह जानना चाहता हूं कि अब हमारे पास C # 4.0 में पैरेलल एक्सटेंशन हैं। फायर एंड फॉरगेट विथ पैरेलल लाइनक करने के लिए बेहतर क्लीनर तरीका है?
जवाबों:
4.0 के लिए उत्तर नहीं है, लेकिन ध्यान देने योग्य है कि .Net 4.5 में आप इसे और भी सरल बना सकते हैं:
#pragma warning disable 4014
Task.Run(() =>
{
MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014
यह चेतावनी चेतावनी को अक्षम करने के लिए है जो आपको बताती है कि आप इस कार्य को आग के रूप में चला रहे हैं और भूल जाते हैं।
यदि घुंघराले ब्रेसिज़ के अंदर विधि एक कार्य देता है:
#pragma warning disable 4014
Task.Run(async () =>
{
await MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014
चलो कि नीचे तोड़:
Task.Run एक कार्य देता है, जो एक संकलक चेतावनी (CS4014) चेतावनी देता है कि इस कोड को पृष्ठभूमि में चलाया जाएगा - यह वही है जो आप चाहते थे, इसलिए हम 4014 चेतावनी अक्षम करते हैं।
डिफ़ॉल्ट रूप से, टास्क "मार्शल को मूल थ्रेड पर वापस लाने का प्रयास करता है," जिसका अर्थ है कि यह टास्क पृष्ठभूमि में चलेगा, फिर उस थ्रेड पर लौटने का प्रयास करें जिसने इसे शुरू किया था। मूल थ्रेड हो जाने के बाद अक्सर आग और भूल कार्य समाप्त करें। यह एक ThreadAbortException को फेंकने का कारण होगा। ज्यादातर मामलों में यह हानिरहित है - यह सिर्फ आपको बता रहा है, मैंने फिर से जुड़ने की कोशिश की, मैं असफल रहा, लेकिन आप किसी भी तरह से परवाह नहीं करते हैं। लेकिन यह अभी भी थोडा शोर है उत्पादन में अपने लॉग में या स्थानीय देव में अपने डिबगर में थ्रेडअबोर्ट्स अपवाद हैं। .ConfigureAwait(false)
सिर्फ साफ रहने और स्पष्ट रूप से कहने का एक तरीका है, इसे पृष्ठभूमि में चलाएं, और यही है।
चूँकि यह वर्डी है, विशेष रूप से बदसूरत प्रज्ञा, मैं इसके लिए एक पुस्तकालय विधि का उपयोग करता हूं:
public static class TaskHelper
{
/// <summary>
/// Runs a TPL Task fire-and-forget style, the right way - in the
/// background, separate from the current thread, with no risk
/// of it trying to rejoin the current thread.
/// </summary>
public static void RunBg(Func<Task> fn)
{
Task.Run(fn).ConfigureAwait(false);
}
/// <summary>
/// Runs a task fire-and-forget style and notifies the TPL that this
/// will not need a Thread to resume on for a long time, or that there
/// are multiple gaps in thread use that may be long.
/// Use for example when talking to a slow webservice.
/// </summary>
public static void RunBgLong(Func<Task> fn)
{
Task.Factory.StartNew(fn, TaskCreationOptions.LongRunning)
.ConfigureAwait(false);
}
}
उपयोग:
TaskHelper.RunBg(async () =>
{
await doSomethingAsync();
}
ConfigureAwait(false)
पर Task.Run
जब तुम नहीं await
काम। फ़ंक्शन का उद्देश्य इसके नाम पर है: "कॉन्फ़िगर प्रतीक्षा "। यदि आप कार्य नहीं await
करते हैं, तो आप एक निरंतरता को पंजीकृत नहीं करते हैं, और जैसा कि आप कहते हैं, "मूल थ्रेड पर वापस मार्शल" कार्य के लिए कोई कोड नहीं है। बड़ा जोखिम एक गैर-अपवादित अपवाद का होता है जिसे अंतिम रूप देने वाले धागे पर पुनर्भरण किया जाता है, जो इस उत्तर को भी संबोधित नहीं करता है।
#Disable Warning BC42358
साथ Task
वर्ग हाँ, लेकिन PLINQ संग्रह से अधिक क्वेरी करने के लिए वास्तव में है।
निम्नलिखित कुछ ऐसा टास्क के साथ करेंगे।
Task.Factory.StartNew(() => FireAway());
या और भी...
Task.Factory.StartNew(FireAway);
या ...
new Task(FireAway).Start();
कहाँ FireAway
है
public static void FireAway()
{
// Blah...
}
इसलिए क्लास और मेथड नेम टेरसिटी के आधार पर, यह आपके द्वारा चुने गए चयन के आधार पर छह और उन्नीस अक्षरों के बीच थ्रेडपूल संस्करण को धड़कता है :)
ThreadPool.QueueUserWorkItem(o => FireAway());
fire and forget in ASP.NET WebForms and windows.close()
?
मेरे पास इस मुद्दे के प्रमुख उत्तर के साथ कुछ मुद्दे हैं।
सबसे पहले, एक सच्ची आग और भूलने की स्थिति में, आप शायद await
काम नहीं करेंगे , इसलिए इसे जोड़ना बेकार है ConfigureAwait(false)
। यदि आप await
द्वारा लौटाया गया मान नहीं है ConfigureAwait
, तो संभवतः इसका कोई प्रभाव नहीं हो सकता है।
दूसरा, आपको इस बात से अवगत होना चाहिए कि जब कार्य अपवाद के साथ पूरा होता है तो क्या होता है। उस सरल समाधान पर विचार करें जो @ ade-miller ने सुझाया है:
Task.Factory.StartNew(SomeMethod); // .NET 4.0
Task.Run(SomeMethod); // .NET 4.5
यह एक खतरे का परिचय देता है: यदि कोई अखंड अपवाद इससे बच जाता है SomeMethod()
, तो वह अपवाद कभी भी नहीं देखा जाएगा, और 1 आपके थ्रेड को क्रैश करते हुए, अंतिम थ्रेड पर पुन: फेंका जा सकता है। इसलिए मैं यह सुनिश्चित करने के लिए एक सहायक विधि का उपयोग करने की सलाह दूंगा कि किसी भी परिणामी अपवाद को देखा जाए।
आप कुछ इस तरह लिख सकते हैं:
public static class Blindly
{
private static readonly Action<Task> DefaultErrorContinuation =
t =>
{
try { t.Wait(); }
catch {}
};
public static void Run(Action action, Action<Exception> handler = null)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
var task = Task.Run(action); // Adapt as necessary for .NET 4.0.
if (handler == null)
{
task.ContinueWith(
DefaultErrorContinuation,
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
else
{
task.ContinueWith(
t => handler(t.Exception.GetBaseException()),
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
}
}
इस कार्यान्वयन में कम से कम ओवरहेड होना चाहिए: कार्य केवल सफलतापूर्वक पूरा नहीं होने पर निरंतरता को लागू किया जाता है, और इसे सिंक्रोनाइज़ किया जाना चाहिए (मूल कार्य से अलग शेड्यूल किए जाने के विपरीत)। "आलसी" मामले में, आप निरंतरता प्रतिनिधि के लिए आवंटन भी नहीं लेंगे।
एक अतुल्यकालिक ऑपरेशन को मारना तब तुच्छ हो जाता है:
Blindly.Run(SomeMethod); // Ignore error
Blindly.Run(SomeMethod, e => Log.Warn("Whoops", e)); // Log error
1. यह .NET 4.0 में डिफ़ॉल्ट व्यवहार था। .NET 4.5 में, डिफ़ॉल्ट व्यवहार को इस तरह से बदल दिया गया था कि अंतिम अपवाद पर अप्रार्थित अपवादों को फिर से नहीं हटाया जाएगा (हालाँकि आप अभी भी उन्हें टास्कस्क्राइडर पर UnobservedTaskException घटना के माध्यम से देख सकते हैं)। हालाँकि, डिफ़ॉल्ट कॉन्फ़िगरेशन ओवरराइड किया जा सकता है, और यहां तक कि अगर आपके एप्लिकेशन को .NET 4.5 की आवश्यकता है, तो आपको यह नहीं मान लेना चाहिए कि अप्रयुक्त कार्य अपवाद हानिरहित होंगे।
ContinueWith
किया जाता है और रद्दीकरण के कारण लागू किया गया था, तो पूर्ववर्ती अपवाद की संपत्ति शून्य होगी और एक शून्य संदर्भ अपवाद फेंक दिया जाएगा। कार्य निरंतरता विकल्प को सेट OnlyOnFaulted
करने के लिए अशक्त जांच या जांच की आवश्यकता को समाप्त कर सकता है यदि अपवाद का उपयोग करने से पहले यह शून्य है।
Task
एक कार्यान्वयन विवरण बन जाता है।
Task
" यह एक समान नहीं है "मुझे पृष्ठभूमि ऑपरेशन को किक करने का एक सरल तरीका चाहिए, इसके परिणाम का कभी भी निरीक्षण न करें, और मुझे परवाह नहीं है कि क्या तंत्र का उपयोग किया जाता है इसे करने के लिए।" उस आधार पर, मैं पूछे गए प्रश्न के अपने उत्तर के पीछे खड़ा हूं ।
fire and forget
में ASP.NET WebForms और windows.close()
?
माइक स्ट्रोबेल के जवाब के साथ होने वाले कुछ मुद्दे को ठीक करने के लिए:
यदि आप उपयोग करते हैं var task = Task.Run(action)
और उस कार्य को जारी रखने के बाद असाइन करते हैं, तो आप Task
अपवाद हैंडलर निरंतरता को असाइन करने से पहले कुछ अपवाद फेंकने के जोखिम में चलेंगे Task
। तो, नीचे का वर्ग इस जोखिम से मुक्त होना चाहिए:
using System;
using System.Threading.Tasks;
namespace MyNameSpace
{
public sealed class AsyncManager : IAsyncManager
{
private Action<Task> DefaultExeptionHandler = t =>
{
try { t.Wait(); }
catch { /* Swallow the exception */ }
};
public Task Run(Action action, Action<Exception> exceptionHandler = null)
{
if (action == null) { throw new ArgumentNullException(nameof(action)); }
var task = new Task(action);
Action<Task> handler = exceptionHandler != null ?
new Action<Task>(t => exceptionHandler(t.Exception.GetBaseException())) :
DefaultExeptionHandler;
var continuation = task.ContinueWith(handler,
TaskContinuationOptions.ExecuteSynchronously
| TaskContinuationOptions.OnlyOnFaulted);
task.Start();
return continuation;
}
}
}
यहां, task
इसे सीधे नहीं चलाया जाता है, इसके बजाय इसे बनाया जाता है, एक निरंतरता असाइन की जाती है, और उसके बाद ही कार्य को पूरा किया जाता है ताकि कार्य जारी करने से पहले कार्य को पूरा करने (या कुछ अपवाद को फेंकने) के जोखिम को खत्म किया जा सके।
यहाँ Run
विधि निरंतरता लौटाती है Task
इसलिए मैं यह सुनिश्चित करने के लिए इकाई परीक्षण लिखने में सक्षम हूं कि निष्पादन पूर्ण है। आप इसे अपने उपयोग में सुरक्षित रूप से अनदेखा कर सकते हैं।