है कि के साथ, अपने कोड ऐसा दिखाई दे सकता (मैं भी बेहतर नाम के लिए कुछ चर को बदल दिया है) मुझे टीपीएल डेटाफ्लो घटकों (जो svick आपको उपयोग करने का सुझाव देता है) पसंद करते हैं, उस सिस्टम पर जाने के लिए पर्याप्त प्रतिबद्धता की आवश्यकता होती है - यह ऐसा कुछ नहीं है जिसे आप किसी मौजूदा डिज़ाइन में जोड़ सकते हैं। यदि आप सीपीयू-गहन डेटा प्रोसेसिंग के उच्च वॉल्यूम कर रहे हैं और कई सीपीयू कोर का फायदा उठाना चाहते हैं तो यह काफी लाभ प्रदान करता है। लेकिन इसमें से सर्वश्रेष्ठ प्राप्त करना गैर-तुच्छ है।
आरएक्स का उपयोग करके उनका अन्य सुझाव, मौजूदा समाधान के साथ एकीकृत करना आसान हो सकता है। (original documentation देखें, लेकिन नवीनतम कोड के लिए, Rx-Main nuget पैकेज का उपयोग करें। या यदि आप स्रोत को देखना चाहते हैं, तो the Rx CodePlex site देखें) यदि आप चाहते हैं तो IEnumerable<Symbol>
का उपयोग करके कॉलिंग कोड को जारी रखना भी संभव होगा - आप एक कार्यान्वयन विस्तार के रूप में पूरी तरह से आरएक्स का उपयोग कर सकते हैं, [2013/11/09 को संपादित करने के लिए:] हालांकि, जैसा कि svick ने इंगित किया है, शायद यह आपके अंतिम लक्ष्य को देखते हुए शायद एक अच्छा विचार नहीं है।
इससे पहले कि मैं आपको एक उदाहरण दिखाने के लिए, मैं वास्तव में क्या हम कर रहे हैं के बारे में स्पष्ट होना चाहता हूँ। आपका उदाहरण इस हस्ताक्षर के साथ एक विधि था: "। यह एक तरीका है कि प्रकार IEnumerable<Symbol>
की एक एकल परिणाम पैदा करता है, और यह कि परिणाम तुरंत उत्पादन नहीं कर सकते हैं"
public async Task<IEnumerable<Symbol>> GetSymbolsAsync()
कि वापसी प्रकार, Task<IEnumerable<Symbol>>
, अनिवार्य रूप से कहते
यह एकल परिणाम बिट है जो मुझे लगता है कि आपको दुःख पैदा हो रहा है, क्योंकि यह वास्तव में आप नहीं चाहते हैं। Task<T>
(कोई फर्क नहीं पड़ता कि T
हो सकता है) एक एकल असीमित ऑपरेशन का प्रतिनिधित्व करता है। इसमें कई कदम हो सकते हैं (await
के कई उपयोग यदि आप इसे C# async
विधि के रूप में कार्यान्वित करते हैं) लेकिन आखिरकार यह एक चीज़ उत्पन्न करता है। आप कई चीजें, अलग-अलग, समय पर उत्पादन करना चाहते हैं, इसलिए Task<T>
एक अच्छा फिट नहीं है।
यदि आप वास्तव में ऐसा करने जा रहे थे जो आपके विधि हस्ताक्षर का वादा करता है - अंततः एक परिणाम उत्पन्न करना - एक तरीका यह है कि आप ऐसा कर सकते हैं कि आपकी एसिंक विधि एक सूची बनाएं और उसके बाद परिणाम के रूप में अच्छा और तैयार हो,
// Note: this first example is *not* what you want.
// However, it is what your method's signature promises to do.
public async Task<IEnumerable<Symbol>> GetSymbolsAsync()
{
var historicalFinancialTask = new List<Task<HistoricalFinancialResult>>();
foreach (var symbol in await _listSymbols)
{
historicalFinancialTask.Add(GetFinancialsQueryAsync(symbol));
}
var results = new List<Symbol>();
while (historicalFinancialTask.Count > 0)
{
var historicalFinancial = await Task.WhenAny(historicalFinancialTask);
historicalFinancialTask.Remove(historicalFinancial);
results.Add(new Symbol(historicalFinancial.Result.Symbol.Identifier, historicalFinancial.Result.Symbol.HistoricalQuotes, historicalFinancial.Result.Data));
}
return results;
}
इस विधि क्या करता है उसके हस्ताक्षर का कहना है: यह एसिंक्रोनस रूप प्रतीकों में से एक दृश्य पैदा करता है।
लेकिन संभवतः आप IEnumerable<Symbol>
बनाना चाहते हैं जो आइटम उपलब्ध होने के बावजूद आइटम उपलब्ध कराते हैं, जब तक कि वे सभी उपलब्ध न हों। (अन्यथा, आप शायद WhenAll
का उपयोग कर सकते हैं।) आप ऐसा कर सकते हैं, लेकिन yield return
कोई रास्ता नहीं है।
संक्षेप में, मुझे लगता है कि आप क्या करना चाहते हैं वह एक असीमित सूची उत्पन्न करता है। वहाँ उस के लिए एक प्रकार है: IObservable<T>
व्यक्त करता है मैं वास्तव में क्या लगता है कि आप अपने Task<IEnumerable<Symbol>>
साथ व्यक्त करने के लिए उम्मीद कर रहे थे: यह आइटम (बस IEnumerable<T>
की तरह), लेकिन अतुल्यकालिक का एक क्रम है।
यह सादृश्य द्वारा यह समझने में मदद कर सकते हैं:
public IObservable<Symbol> GetSymbolsObservable() ...
:
public Symbol GetSymbol() ...
को
public Task<Symbol> GetSymbolAsync() ...
रूप
public IEnumerable<Symbol> GetSymbols() ...
है है
(दुर्भाग्यवश, Task<T>
के विपरीत, एक असीमित अनुक्रम-उन्मुख विधि को कॉल करने के लिए एक सामान्य नामकरण सम्मेलन नहीं है। मैंने अंत में 'अवलोकन' जोड़ा है, लेकिन यह सार्वभौमिक अभ्यास नहीं है। । मैं निश्चित रूप से यह GetSymbolsAsync
फोन नहीं है, क्योंकि लोगों को वापस जाने के लिए उम्मीद करेंगे एक Task
)
दूसरे शब्दों में कहें करने के लिए, Task<IEnumerable<T>>
कहते हैं जबकि IObservable<T>
कहते हैं, "मैं इस संग्रह जब मैं अच्छा और तैयार हूँ उत्पादन होगा": "यहां एक संग्रह है। जब मैं अच्छा और तैयार हूं तो मैं प्रत्येक आइटम का उत्पादन करूंगा।"
तो, आप के लिए एक विधि है कि Symbol
वस्तुओं, जहां उन वस्तुओं एसिंक्रोनस रूप से उत्पादित कर रहे हैं का एक अनुक्रम रिटर्न चाहते हैं। यह हमें बताता है कि आपको वास्तव में IObservable<Symbol>
लौटाना चाहिए।यहाँ एक कार्यान्वयन है:
// Unlike this first example, this *is* what you want.
public IObservable<Symbol> GetSymbolsRx()
{
return Observable.Create<Symbol>(async obs =>
{
var historicalFinancialTask = new List<Task<HistoricalFinancialResult>>();
foreach (var symbol in await _listSymbols)
{
historicalFinancialTask.Add(GetFinancialsQueryAsync(symbol));
}
while (historicalFinancialTask.Count > 0)
{
var historicalFinancial = await Task.WhenAny(historicalFinancialTask);
historicalFinancialTask.Remove(historicalFinancial);
obs.OnNext(new Symbol(historicalFinancial.Result.Symbol.Identifier, historicalFinancial.Result.Symbol.HistoricalQuotes, historicalFinancial.Result.Data));
}
});
}
आप देख सकते हैं, यह आप काफी बारे में क्या आप लिखने के लिए उम्मीद कर रहे थे की सुविधा देता है - इस कोड के शरीर तुम्हारा के लगभग समान है। केवल अंतर यह है कि आप yield return
(जो संकलित नहीं किया गया था) का उपयोग कर रहे थे, यह आरएक्स द्वारा प्रदान की गई वस्तु पर OnNext
विधि को कॉल करता है।
लिखा करने के बाद, आप आसानी से एक IEnumerable<Symbol>
में इस लपेट कर सकते हैं ([जोड़ने के लिए संपादित 2013/11/29:] हालांकि आप शायद नहीं वास्तव में ऐसा करना चाहते हैं - जवाब के अंत में इसके अलावा देखें):
public IEnumerable<Symbol> GetSymbols()
{
return GetSymbolsRx().ToEnumerable();
}
यह अतुल्यकालिक नहीं लग सकता है, लेकिन यह वास्तव में अंतर्निहित कोड एसिंक्रोनस रूप से संचालित करने के लिए अनुमति नहीं है। जब आप इस विधि को कॉल करते हैं, तो यह अवरुद्ध नहीं होगा - भले ही अंतर्निहित कोड जो वित्तीय जानकारी लाने का काम करता है, तुरंत परिणाम नहीं दे सकता है, फिर भी यह विधि तुरंत IEnumerable<Symbol>
लौटाएगी। अब निश्चित रूप से, कोई भी कोड जो उस संग्रह के माध्यम से पुन: प्रयास करने का प्रयास करता है, यदि डेटा अभी तक उपलब्ध नहीं है तो अवरुद्ध हो जाएगा।
- आपको लगता है कि
Observable.Create<T>
को काम (मेरे उदाहरण में एक प्रतिनिधि, एक तर्क के रूप में पारित करता है एक async
विधि लिखने के लिए मिलता है, लेकिन आप कर सकते थे: लेकिन महत्वपूर्ण बात यह है कि मैं क्या लगता है कि आप मूल रूप से प्राप्त करने के लिए कोशिश कर रहे थे करता है यदि आप चाहें तो एक स्टैंडअलोन async
विधि लिखना)
- बुला कोड प्रतीकों लाना प्रारंभ करने के लिए कहेगा का परिणाम के रूप में केवल अवरुद्ध नहीं किया जाएगा
IEnumerable<Symbol>
जिसके परिणामस्वरूप जैसे ही यह उपलब्ध हो जाता है प्रत्येक व्यक्ति के मद का उत्पादन करेगा
यह काम करता है क्योंकि आरएक्स की ToEnumerable
विधि में कुछ चालाक कोड है जो IEnumerable<T>
के सिंक्रोनस वर्ल्ड व्यू और परिणामों के असीमित उत्पादन के बीच अंतर को पुल करता है। (दूसरे शब्दों में, यह ठीक है कि आप सी # को खोजने में निराश थे, जो आपके लिए करने में सक्षम नहीं था।)
यदि आप उत्सुक हैं, तो आप स्रोत को देख सकते हैं। कोड है कि underlies क्या ToEnumerable
करता https://rx.codeplex.com/SourceControl/latest#Rx.NET/Source/System.Reactive.Linq/Reactive/Linq/Observable/GetEnumerator.cs
में पाया जा सकता [संपादित 2013/11/29 जोड़ने के लिए:]
svick टिप्पणियां कुछ मैं याद में बताया गया है: अपने अंतिम लक्ष्य डाल करने के लिए है ObservableCollection<Symbol>
में सामग्री। किसी तरह मैंने उस बिट को नहीं देखा। इसका मतलब है कि IEnumerable<T>
जाने का गलत तरीका है - आप foreach
लूप के साथ करने के बजाय, आइटम को उपलब्ध होने के रूप में संग्रह को पॉप्युलेट करना चाहते हैं। तो आप बस यह करेंगे:
GetSymbolsRx().Subscribe(symbol => SymbolsObservableCollection.Add(symbol));
या उन पंक्तियों के साथ कुछ। इससे संग्रह में वस्तुओं को और जब वे उपलब्ध हो जाएंगे।
यह यूआई थ्रेड पर पूरी तरह से लात मारने पर निर्भर करता है। जब तक यह है, आपका एसिंक कोड UI थ्रेड पर चलना समाप्त हो जाना चाहिए, जिसका अर्थ है कि जब संग्रह में आइटम जोड़े जाते हैं, तो यह यूआई थ्रेड पर भी होता है।लेकिन अगर किसी कारण से आप एक कार्यकर्ता धागे से बातें शुरू करने अंत (या आप प्रतीक्षा कर रहा है में से किसी पर ConfigureAwait
उपयोग करने के लिए, इस प्रकार यूआई धागा के सिलसिले को तोड़ने के थे तो) आप आरएक्स से आइटम को संभालने के लिए व्यवस्था करने के लिए आवश्यकता होगी सही धागे पर धारा:
GetSymbolsRx()
.ObserveOnDispatcher()
.Subscribe(symbol => SymbolsObservableCollection.Add(symbol));
आप यूआई धागे पर कर रहे हैं जब आप करते हैं कि, यह वर्तमान डिस्पैचर लेने आऊँगा, और यह सुनिश्चित सभी सूचनाएं इसके माध्यम से आते हैं तो। यदि आप सदस्यता लेने के लिए पहले से ही गलत धागे पर हैं, तो आप ObserveOn
अधिभार का उपयोग कर सकते हैं जो एक प्रेषक लेता है। (ये System.Reactive.Windows.Threading
के लिए एक संदर्भ करने का आग्रह कर और इन विस्तार तरीके हैं, तो आप उनके युक्त नाम स्थान है, जो भी System.Reactive.Windows.Threading
कहा जाता है के लिए एक using
आवश्यकता होगी।)
Btw, पूरा होने के अपने आदेश से 'Task's का एक संग्रह पर कार्रवाई करने के, पर एक नजर है [' OrderByCompletion() '] (http://nitoasyncex.codeplex.com/wikipage?title=TaskExtensions&referringTitle=Documentation) से निटो AsyncEx। – svick
आप [रिएक्टिव एक्सटेंशन (आरएक्स)] को देखा है (http://msdn.microsoft.com/en-us/data/gg577609.aspx)? –
मेरे पास है, लेकिन अस्तर वक्र मेरे लिए बहुत अधिक है और वास्तव में मुझे समझ नहीं आता क्या माइक्रोसॉफ्ट इस प्रौद्योगिकी के भविष्य पर विचार कर रहा है क्योंकि वे भी TPL Dataflow जो एक ही काम करते हैं थोड़े लगता है। जिस समस्या में मैं यहां पूछ रहा हूं वह इतना आसान है, इसलिए समाधान भी सरल होना चाहिए। और मुझे अभी भी समझ में नहीं आ रहा है कि क्यों वे .NET Framework में आरएक्स या डेटाफ्लो शामिल नहीं करते हैं, ऐसा लगता है कि वे इन दो ढांचे को भी शामिल करने के लिए पर्याप्त भरोसा नहीं करते हैं। – Gui