मैंने एक कस्टम TaskScheduler
लिखा है जो एक ही थ्रेड पर दिए गए कार्यों को निष्पादित करने वाला है। इस कार्य शेड्यूलर का उपयोग कस्टम कार्य फ़ैक्टरी के साथ किया जाता है। यह कार्य कारखाना एक एसिंक विधि ReadFileAsync
निष्पादित करता है जो StreamReader
की एक अन्य एसिंक विधि ReadToEndAsync
कहता है।
मैंने देखा है कि ReadToEndAsync().ConfigureAwait(false)
का उपयोग करने के बाद, वर्तमान कार्य अनुसूचक को वापस डिफ़ॉल्ट एक, ThreadPoolTaskScheduler
पर वापस कर दिया जाता है। अगर मैं ConfigureAwait(false)
को हटा देता हूं, तो कस्टम टास्क शेड्यूलर SameThreadTaskScheduler
रखा जाता है। क्यों? क्या इसके निष्पादन के बाद उसी कस्टम शेड्यूलर के साथ ConfigureAwait(false)
का उपयोग करने का कोई तरीका है?
मैंने कई चीजों की कोशिश की है, लेकिन नतीजा वही है:
- कस्टम
TaskFactory
के एनम झंडे बदलें - एक कस्टम सिंक्रोनाइज़ेशन संदर्भ का उपयोग करना जो
Posts
कॉलबैक को थ्रेड पूल के बजाय सिंक्रोनाइज़ करता है - कार्य फ़ैक्टरी पर निष्पादित कार्य फ़ंक्शन के अंदर सिंक्रनाइज़ेशन को बदलें और वापस लाएं
- कार्य फ़ैक्टरी पर निष्पादित कार्य फ़ंक्शन के बाहर सिंक्रनाइज़ेशन को बदलें और वापस लाएं
public static class Program
{
private static readonly string DesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
public static void Main()
{
_ = AsyncHelper.RunSynchronously(ReadFileAsync);
}
private static async Task<string> ReadFileAsync()
{
// Prints "SameThreadTaskScheduler"
Console.WriteLine(TaskScheduler.Current.GetType().Name);
using var fs = File.OpenText(Path.Combine(DesktopPath, "hello.txt"));
var content = await fs.ReadToEndAsync().ConfigureAwait(false); // <-------- HERE
// With ReadToEndAsync().ConfigureAwait(false), prints "ThreadPoolTaskScheduler"
// With ReadToEndAsync() only, prints "SameThreadTaskScheduler"
Console.WriteLine(TaskScheduler.Current.GetType().Name);
return content;
}
}
public static class AsyncHelper
{
private static readonly TaskFactory SameThreadTaskFactory = new TaskFactory(
CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
new SameThreadTaskScheduler());
public static TResult RunSynchronously<TResult>(Func<Task<TResult>> func)
{
var oldContext = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(null);
return SameThreadTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
finally
{
SynchronizationContext.SetSynchronizationContext(oldContext);
}
}
}
public sealed class SameThreadTaskScheduler : TaskScheduler
{
public override int MaximumConcurrencyLevel => 1;
protected override void QueueTask(Task task)
{
this.TryExecuteTask(task);
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
this.TryExecuteTask(task);
return true;
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
}
1 उत्तर
ConfigureAwait(bool continueOnCapturedContext)
में पैरामीटर continueOnCapturedContext
का निम्नलिखित अर्थ है: यदि true
निर्दिष्ट है, तो इसका मतलब है कि निरंतरता को कैप्चर किए गए मूल संदर्भ में वापस मार्शल किया जाना चाहिए। यदि false
निर्दिष्ट है, तो निरंतरता एक मनमाना संदर्भ पर चल सकती है।
सिंक्रोनाइज़ेशन संदर्भ शेड्यूलिंग के लिए एक अमूर्त है। एक TaskScheduler
एक ठोस कार्यान्वयन है। तो ConfigureAwait(false)
निर्दिष्ट करके, आप कहते हैं कि किसी भी कार्य शेड्यूलर का उपयोग किया जा सकता है। यदि आप अपने विशेष कार्य शेड्यूलर का उपयोग करना चाहते हैं, तो ConfigureAwait(true)
का उपयोग करें।
इस विषय पर अधिक जानकारी के लिए, इस पोस्ट पर एक नज़र डालें।
संबंधित सवाल
नए सवाल
c#
C # (उच्चारण "तेज देखें") Microsoft द्वारा विकसित एक उच्च स्तरीय, सांख्यिकीय रूप से टाइप किया हुआ, बहु-प्रतिमान प्रोग्रामिंग भाषा है। C # कोड आमतौर पर Microsoft के .NET परिवार के टूल और रन-टाइम को लक्षित करता है, जिसमें .NET फ्रेमवर्क, .NET कोर और Xamarin अन्य शामिल हैं। C # या C # के औपचारिक विनिर्देश में लिखे गए कोड के बारे में प्रश्नों के लिए इस टैग का उपयोग करें।
ConfigureAwait(false)
को क्यों कॉल कर रहे हैं।ConfigureAwait(false)
वही करता है जो करना चाहिए। जो थोड़े अजीब है। यह पूछने जैसा है कि+
ऑपरेटर अतिरिक्त क्यों करता है, और आप इसे जोड़ने से कैसे रोक सकते हैं। अच्छी तरह से ठीक है। यदि आपको यह पसंद नहीं है किConfigureAwait(false)
await
को कॉन्फ़िगर करता है ताकि यह वर्तमान संदर्भ या शेड्यूलर को कैप्चर न करे, तो आप इसे क्या करना चाहेंगे? क्या आप इसे नो-ऑप बनाना चाहेंगे?AsyncLocal<T>
से इसे पूरा किया जा सकता है? क्या आप एसिंक्रोनस कोड को ब्लॉक कर रहे हैं?ConfigureAwait(false)
के साथ async को कॉल करने के बाद वर्तमान कस्टम कार्य शेड्यूलर क्यों बदलता है। आपकी टिप्पणियों और उत्तरों के साथ, अब मैं समझ गया!HttpWebRequest
के उपयोग कोHttpClient
से बदलना पड़ा। सबसे पहले, मैंने देखा कि यह कस्टम थ्रेड-सीमक कार्य शेड्यूलर का उपयोग कर रहा था, जिसके परिणामस्वरूप थ्रेड भुखमरी हुई। इसलिए मैं यह सुनिश्चित करने का प्रयास कर रहा हूं किHttpClient
async विधियों और कॉलबैक को उसी थ्रेड पर किसी अन्य कार्य शेड्यूलर के साथ निष्पादित किया गया था।