2012-12-01 11 views
5

बाद में निष्पादन के लिए मैं TPL- आधारित कार्यों के List<T> को कैसे विलय करूं?मैं दो लिंक INumerable <T> क्वेरी चलाने के बिना कैसे विलय कर सकता हूं?

public async IEnumerable<Task<string>> CreateTasks(){ /* stuff*/ } 

मेरे धारणा .Concat() है ...

 void MainTestApp() // Full sample available upon request. 
    { 
     List<string> nothingList = new List<string>(); 
     nothingList.Add("whatever"); 
     cts = new CancellationTokenSource(); 

     delayedExecution = 
      from str in nothingList 
      select AccessTheWebAsync("", cts.Token); 
     delayedExecution2 = 
      from str in nothingList 
      select AccessTheWebAsync("1", cts.Token); 

     delayedExecution = delayedExecution.Concat(delayedExecution2); 
    } 


    /// SNIP 

    async Task AccessTheWebAsync(string nothing, CancellationToken ct) 
    { 
     // return a Task 
    } 

मुझे यकीन है कि यह किसी भी काम के लिए अंडे नहीं होगा या कुछ भी मूल्यांकन करना चाहते हैं। असल में, मुझे लगता है कि मैं पूछ रहा हूं "डेटा लौटने वाले किसी चीज़ के लिए एक IQueryable को तर्कसंगत रूप से निष्पादित करता है"?

पृष्ठभूमि

जब से मैं प्रत्यावर्तन कर रहा हूँ और मैं सही समय है जब तक इस पर अमल नहीं करना चाहती, अगर कहा जाता है कई बार परिणाम विलय करने के लिए सही तरीका क्या है?

यह मायने रखता है कि मैं सभी कार्य var AllRunningDataTasks = results.ToList(); इस कोड के बाद शुरू करने के लिए इस आदेश को चलाने का सोच रहा हूँ, तो:

while (AllRunningDataTasks.Count > 0) 
{ 
    // Identify the first task that completes. 
    Task<TableResult> firstFinishedTask = await Task.WhenAny(AllRunningDataTasks); 

    // ***Remove the selected task from the list so that you don't 
    // process it more than once. 
    AllRunningDataTasks.Remove(firstFinishedTask); 

    // TODO: Await the completed task. 
    var taskOfTableResult = await firstFinishedTask; 

    // Todo: (doen't work) 
    TrustState thisState = (TrustState)firstFinishedTask.AsyncState; 

    // TODO: Update the concurrent dictionary with data 
    // thisState.QueryStartPoint + thisState.ThingToSearchFor 

    Interlocked.Decrement(ref thisState.RunningDirectQueries); 
    Interlocked.Increment(ref thisState.CompletedDirectQueries); 

    if (thisState.RunningDirectQueries == 0) 
    { 
     thisState.TimeCompleted = DateTime.UtcNow; 
    } 
} 
+0

क्यों संगत काम नहीं कर रहा है, इसे काम करना चाहिए? साथ ही, आप कार्य नहीं करना चाहते हैं, लेकिन क्वेरी चलाना ठीक है, आरटीटी? – Tilak

+0

@ टिलक मेरा ध्यान कार्य पर है, और यह पहली बार कार्य या प्रश्नों पर ऐसा करने वाला है। मैंने कभी प्रश्नों के साथ ऐसा नहीं किया, लेकिन मुझे याद है कि कंसट यह है कि यह कैसे किया जाता है। – LamonteCristo

+0

@ टिलक शायद मुझे अपने कोड में एक बग मिला ... जल्द ही अपडेट हो जाएगा – LamonteCristo

उत्तर

0

निम्न डेटा विलय कर दिया पाने के लिए एक hacky तरीका है ... मैं नहीं जैसे कि मुझे मुख्य या कुछ नमूने के कुछ अन्य पहलुओं में "कुछ भी नहीं" का उपयोग करना था, लेकिन ऐसा लगता है कि काम पूरा हो गया है और मुझे लंबित कार्यों को मर्ज करने की अनुमति है।

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

// Add a using directive and a reference for System.Net.Http. 
using System.Net.Http; 

// Add the following using directive. 
using System.Threading; 


namespace ProcessTasksAsTheyFinish 
{ 
    public partial class MainWindow : Window 
    { 
     // Declare a System.Threading.CancellationTokenSource. 
     CancellationTokenSource cts; 
     List<IEnumerable<Task>> launchList = new List<IEnumerable<Task>>(); 

     public MainWindow() 
     { 
      InitializeComponent(); 

      List<string> nothingList = new List<string>(); 
      nothingList.Add("whatever"); 

      cts = new CancellationTokenSource(); 

      delayedExecution = 
       from str in nothingList 
       select AccessTheWebAsync("", cts.Token); 


      List<string> nothingList2 = new List<string>(); 
      nothingList2.Add("whatever"); 

      delayedExecution2 = 
       from str in nothingList2 
       select AccessTheWebAsync("1", cts.Token); 


      launchList.Add(delayedExecution); 
      launchList.Add(delayedExecution2); 

      delayedExecution = delayedExecution.Concat(delayedExecution2); 
     } 
     IEnumerable<Task> delayedExecution = null; 
     IEnumerable<Task> delayedExecution2 = null; 

     private async void startButton_Click(object sender, RoutedEventArgs e) 
     { 
      resultsTextBox.Clear(); 

      // Instantiate the CancellationTokenSource. 

      try 
      { 
       // ***Set up the CancellationTokenSource to cancel after 25 seconds. 
       //cts.CancelAfter(250000); 

       var test = delayedExecution;// AccessTheWebAsync("", cts.Token); 

       var testList = test.ToList(); 

       while (testList.Count() > 0) 
       { 
        var firstFinishedTask = await Task.WhenAny(testList); 
        testList.Remove(firstFinishedTask); 

         await firstFinishedTask; 
       } 

       resultsTextBox.Text += "\r\nDownloads complete."; 
      } 
      catch (OperationCanceledException tee) 
      { 
       resultsTextBox.Text += "\r\nDownloads canceled.\r\n"; 
      } 
      catch (Exception) 
      { 
       resultsTextBox.Text += "\r\nDownloads failed.\r\n"; 
      } 

      cts = null; 
     } 


     private void cancelButton_Click(object sender, RoutedEventArgs e) 
     { 
      if (cts != null) 
      { 
       cts.Cancel(); 
      } 
     } 


     async Task<string> AccessTheWebAsync(string nothing, CancellationToken ct) 
     { 
      // CHANGE THIS VALUE TO CONTROL THE TESTING 
      bool delayConversionOfQueryToList = false; 

      HttpClient client = new HttpClient(); 

      // Make a list of web addresses. 
      List<string> urlList = null; 

      if (nothing == "1") 
      { 
       urlList = SetUpURLList2(); 
      } 
      else urlList = SetUpURLList(); 

      // ***Create a query that, when executed, returns a collection of tasks. 
      IEnumerable<Task<int>> downloadTasksQuery = 
       from url in urlList select ProcessURL(url, client, ct); 

      // DEBUG!!! 
      if (delayConversionOfQueryToList == true) 
      { 
       await Task.Delay(10000); 
       resultsTextBox.Text += String.Format("\r\nDelay of IQueryable complete. Tip: Did you see any IsRunning messages?"); 
      } 

      // ***Use ToList to execute the query and start the tasks. 
      List<Task<int>> downloadTasks = downloadTasksQuery.ToList(); 

      // DEBUG!!! 
      if (delayConversionOfQueryToList == false) 
      { 
       await Task.Delay(10000); 
       resultsTextBox.Text += String.Format("\r\nDelay of .ToList() complete. Tip: Did you see any IsRunning messages?"); 
      } 

      // ***Add a loop to process the tasks one at a time until none remain. 
      while (downloadTasks.Count() > 0) 
      { 
       // Identify the first task that completes. 
       Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks); 

       resultsTextBox.Text += String.Format("\r\nID {0}", firstFinishedTask.Id); 

       // ***Remove the selected task from the list so that you don't 
       // process it more than once. 
       downloadTasks.Remove(firstFinishedTask); 

       // Await the completed task. 
       int length = await firstFinishedTask; 
       resultsTextBox.Text += String.Format("\r\nLength of the download: {0}", length); 
      } 

      return nothing; 
     } 


     private List<string> SetUpURLList() 
     { 
      List<string> urls = new List<string> 
      { 
       "http://msdn.microsoft.com", 
       "http://msdn.microsoft.com/library/windows/apps/br211380.aspx", 
       "http://msdn.microsoft.com/en-us/library/hh290136.aspx", 
       "http://msdn.microsoft.com/en-us/library/dd470362.aspx", 
       "http://msdn.microsoft.com/en-us/library/aa578028.aspx", 
       "http://msdn.microsoft.com/en-us/library/ms404677.aspx", 
       "http://msdn.microsoft.com/en-us/library/ff730837.aspx" 
      }; 
      return urls; 
     } 
     private List<string> SetUpURLList2() 
     { 
      List<string> urls = new List<string> 
      { 
       "http://www.google.com", 

      }; 
      return urls; 
     } 

     async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct) 
     { 
      resultsTextBox.Text += String.Format("\r\nIS RUNNING {0}", url); 

      // GetAsync returns a Task<HttpResponseMessage>. 
      HttpResponseMessage response = await client.GetAsync(url, ct); 
      // Retrieve the website contents from the HttpResponseMessage. 
      byte[] urlContents = await response.Content.ReadAsByteArrayAsync(); 

      // Thread.Sleep(3000); 
      // await Task.Delay(1000, ct); 
      return urlContents.Length; 
     } 
    } 
} 

// Sample Output: 

IS RUNNING http://msdn.microsoft.com 
IS RUNNING http://msdn.microsoft.com/library/windows/apps/br211380.aspx 
IS RUNNING http://msdn.microsoft.com/en-us/library/hh290136.aspx 
IS RUNNING http://msdn.microsoft.com/en-us/library/dd470362.aspx 
IS RUNNING http://msdn.microsoft.com/en-us/library/aa578028.aspx 
IS RUNNING http://msdn.microsoft.com/en-us/library/ms404677.aspx 
IS RUNNING http://msdn.microsoft.com/en-us/library/ff730837.aspx 
IS RUNNING http://www.google.com 
Delay of .ToList() complete. Tip: Did you see any IsRunning messages? 
ID 1 
Length of the download: 48933 
ID 2 
Length of the download: 375328 
ID 3 
Length of the download: 220428 
ID 4 
Length of the download: 222256 
ID 5 
Length of the download: 229330 
ID 6 
Length of the download: 136544 
ID 7 
Length of the download: 207171 
Delay of .ToList() complete. Tip: Did you see any IsRunning messages? 
ID 8 
Length of the download: 43945 
Downloads complete. 
2

विशिष्ट प्रश्न का उत्तर देने के लिए "डेटा लौटने वाले किसी चीज़ के लिए एक IQueryable को तर्कसंगत रूप से निष्पादित करता है"? यह कुछ भी होगा जो या तो कम से कम एक मूल्य के उत्पादन को मजबूर करता है, या यह पता चलता है कि कोई मूल्य उपलब्ध है या नहीं।

उदाहरण, ToList, ToArray, First, Single, SingleOrDefault के लिए, और Count सभी बल मूल्यांकन होगा। (हालांकि First पूरे संग्रह का मूल्यांकन नहीं करेगा - यह पहले आइटम को पुनर्प्राप्त करेगा और फिर रुक जाएगा।) इन सभी को कम से कम मूल्यों को पुनर्प्राप्त करना शुरू करना होगा, क्योंकि उनमें से किसी के बिना ऐसा करने के लिए वापस आने का कोई तरीका नहीं है। ToList और ToArray के मामले में, ये पूरी तरह से आबादी वाले गैर-आलसी संग्रह लौटते हैं, यही कारण है कि उन्हें सबकुछ का मूल्यांकन करना है। एक आइटम को वापस करने वाली विधियों को कम से कम पहले आइटम के लिए पूछना आवश्यक है, और Single फिर यह जांचने के लिए आगे बढ़ेंगे कि अगर मूल्यांकन जारी रहता है तो कुछ भी नहीं निकलता है (और यदि अधिक हो जाता है तो अपवाद फेंक दें)।

क्वेरी पर पुनरावृत्त करने के लिए foreach का उपयोग करके मूल्यांकन को भी बल दिया जाएगा। (और फिर, यह वही कारण है: आप इसे संग्रह से वास्तविक मूल्यों के लिए पूछ रहे हैं, इसलिए इसे उन्हें प्रदान करना होगा।)

Concat तत्काल मूल्यांकन नहीं करता है क्योंकि इसकी आवश्यकता नहीं है - यह केवल तभी होता है जब आप एक मूल्य के लिए समेकित अनुक्रम से पूछें कि इसे मूल्यों के लिए अपने इनपुट पूछने की आवश्यकता है।

बीटीडब्ल्यू, हालांकि आपने IQueryable के बारे में पूछा है, तो आप यहां उदाहरणों में इसका उपयोग नहीं कर रहे हैं। इससे कोई फर्क नहीं पड़ता है, क्योंकि LINQ से ऑब्जेक्ट्स कार्यान्वयन (जो आपको सादा IEnumerable<T> के लिए मिलता है) की तुलना में यह कैसे काम करता है, इसमें कुछ अंतर हैं जो आप वास्तव में प्राप्त कर रहे हैं। मुझे नहीं लगता कि इससे इस उदाहरण में कोई फर्क पड़ता है, लेकिन यह मुझे आश्चर्यचकित करता है कि क्या आपके मूल कोड और आपके द्वारा चित्रण के लिए पोस्ट किए गए संस्करण के बीच कुछ बदलाव हो सकता है? इससे कोई फर्क नहीं पड़ता क्योंकि विभिन्न LINQ प्रदाता विभिन्न तरीकों से काम कर सकते हैं।IEnumerable<T>Concat का स्वाद निश्चित रूप से स्थगित मूल्यांकन का उपयोग करता है, और हालांकि मैं उम्मीद करता हूं कि यह अधिकांश अन्य LINQ कार्यान्वयन के लिए सच साबित होगा, यह बिल्कुल बिल्कुल नहीं दिया गया है।

यदि आपको कई बार परिणामों का उपयोग करने की आवश्यकता है, और आप यह सुनिश्चित करना चाहते हैं कि आप केवल एक बार उनका मूल्यांकन करें, लेकिन जब तक आपको वास्तव में उनकी आवश्यकता न हो, तब तक आप उनका मूल्यांकन नहीं करते हैं, तो सामान्य दृष्टिकोण ToList पर कॉल करना है बिंदु जहां आपको निश्चित रूप से मूल्यांकन करने की आवश्यकता है, और फिर परिणामस्वरूप List<T> पर रखें ताकि आप इसे फिर से उपयोग कर सकें। एक बार जब आप List<T> (या सरणी) रूप में डेटा प्राप्त कर लेंगे तो आप उस सूची का जितनी बार चाहें उतनी बार उपयोग कर सकते हैं।

वैसे, अपने पहले प्रश्न एक मुद्दा है: "मैं बाद में निष्पादन के लिए TPL आधारित कार्यों की एक सूची कैसे मर्ज है"

सामान्यतः, यदि आपके पास पहले से ही एक टीपीएल कार्य है तो आप इसे निष्पादित करने से नहीं रोक सकते हैं। (इसमें एक अपवाद है। यदि आप इसे बनाने के अधिक सामान्य तरीकों में से एक का उपयोग करने के बजाय सीधे Task बनाते हैं, तो यह वास्तव में तब तक नहीं चलता जब तक आप इसे नहीं बताते। लेकिन आम तौर पर, एपीआई जो कार्य वापस लौटाते हैं , यानी, जब तक आप उन पर अपना हाथ प्राप्त करते हैं, तब तक वे पहले से ही चल रहे हैं, या यहां तक ​​कि पूर्ण हो सकते हैं।)

आपके उदाहरण में "बाद में निष्पादन" इस तथ्य से आता है कि आपके पास वास्तव में कोई सूची नहीं है सभी के साथ शुरू करने के लिए कार्य। (यदि आपके पास वास्तव में List<T> कार्यों का है, तो "बाद में निष्पादन" एक विकल्प नहीं होगा।) आपके पास जो कुछ है, वह है जो, यदि आप उनका मूल्यांकन करना चाहते हैं, तो कार्य बनाएंगे। कार्य बनाने का कार्य किसी भी टीएपी-शैली एपीआई में शुरू करने के कार्य से अविभाज्य है जो कार्य देता है।

आप क्या लिखा है के बाकी के आधार पर, मुझे लगता है कि आप वास्तव में क्या कह रहे हैं यह है:

"मैं एक तरीका है कि अंतर्निहित enumerables के मूल्यांकन defers में एक भी IEnumerable<Task<T>> में IEnumerable<Task<T>> वस्तुओं कई मर्ज करते जब तक संयुक्त गणित का मूल्यांकन नहीं किया जाता है? "

Concat इसके लिए काम करना चाहिए।

+0

दिलचस्प ... मैं लोड-ऑन-डिमांड पेड़ प्राप्त करने के लिए एज़ूर स्टोरेज का उपयोग कर रहा हूं और मैं उप-नोड्स को तब तक निष्पादित नहीं करना चाहता एक ही गहराई में सभी शाखाओं की खोज की गई है। Azure भंडारण शुरू होता है .. एंड अर्थशास्त्र। मैं उन्हें यहां वर्णित टीपीएल में लपेट रहा हूं http://stackoverflow.com/q/13216475/328397 – LamonteCristo

संबंधित मुद्दे

 संबंधित मुद्दे