13

मुझे यह समझने में समस्या है कि AttachedToParent पैरामीटर कैसे काम करता है।संलग्न टॉपरेंट टास्क भ्रम

public static void Main(string[] args) 
    { 
     Task<int[]> parentTask = Task.Run(()=> 
     { 
      int[] results = new int[3]; 

      Task t1 = new Task(() => { Thread.Sleep(3000); results[0] = 0; }, TaskCreationOptions.AttachedToParent); 
      Task t2 = new Task(() => { Thread.Sleep(3000); results[1] = 1; }, TaskCreationOptions.AttachedToParent); 
      Task t3 = new Task(() => { Thread.Sleep(3000); results[2] = 2; }, TaskCreationOptions.AttachedToParent); 

      t1.Start(); 
      t2.Start(); 
      t3.Start(); 

      return results; 
     }); 

     Task finalTask = parentTask.ContinueWith(parent => 
     { 
      foreach (int result in parent.Result) 
      { 
       Console.WriteLine(result); 
      } 
     }); 

     finalTask.Wait(); 
     Console.ReadLine(); 
    } 

मैं समझता हूँ के रूप में, जब एक टास्क बच्चे कार्य है, माता पिता के कार्य खत्म जब सभी बच्चे कार्यों के लिए तैयार हैं:

यहाँ नमूना कोड है। इस उदाहरण के साथ समस्या यह है कि उत्पादन इस तरह दिखता है:

0 
0 
0 

इसका मतलब यह है कि माता-पिता टास्क अपने बच्चे को कार्य समाप्त करने के लिए के लिए इंतजार नहीं कर रहा था। एक वैध परिणाम 0 1 2 प्राप्त करने के लिए एक ही रास्ता बच्चा taks के सभी पर प्रतीक्षा उपयोग करने के लिए, return results; बयान से पहले इस तरह कोड के कुछ टुकड़े जोड़कर है:

Task[] taskList = { t1, t2, t3 }; 
Task.WaitAll(taskList); 

मेरा प्रश्न यह है। हम TaskCreationOptions.AttachedToParent का उपयोग क्यों करते हैं जब हमें प्रत्येक बच्चे के कार्य के लिए प्रतीक्षा विधि को मैन्युअल रूप से कॉल करना होगा?

संपादित करें:

जबकि मैं इस सवाल लिख रहा था, मैं कोड एक छोटा सा बदल दिया है और अब AttachedToParent अच्छी तरह से काम करता है। केवल अंतर यह है कि मैंने Task.Run(); के बजाय parentTask.Start(); का उपयोग किया है।

public static void Main(string[] args) 
    { 
     Task<int[]> parentTask = new Task<int[]>(()=> 
     { 
      int[] results = new int[3]; 

      Task t1 = new Task(() => { Thread.Sleep(3000); results[0] = 0; }, TaskCreationOptions.AttachedToParent); 
      Task t2 = new Task(() => { Thread.Sleep(3000); results[1] = 1; }, TaskCreationOptions.AttachedToParent); 
      Task t3 = new Task(() => { Thread.Sleep(3000); results[2] = 2; }, TaskCreationOptions.AttachedToParent); 

      t1.Start(); 
      t2.Start(); 
      t3.Start(); 

      //Task[] taskList = { t1, t2, t3 }; 
      //Task.WaitAll(taskList); 

      return results; 
     }); 

     parentTask.Start(); 

     Task finalTask = parentTask.ContinueWith(parent => 
     { 
      foreach (int result in parent.Result) 
      { 
       Console.WriteLine(result); 
      } 
     }); 

     finalTask.Wait(); 
     Console.ReadLine(); 
    } 

मुझे अभी भी समझ में नहीं आता कि पहले उदाहरण में कोई समस्या क्यों है। इस ब्लॉग पोस्ट पर

उत्तर

19

देखो: Task.Run vs Task.Factory.StartNew

पहला उदाहरण:

Task.Run(someAction); 

विधि के बराबर सरल है:

Task.Factory.StartNew(someAction, 
     CancellationToken.None, 
     TaskCreationOptions.DenyChildAttach, 
     TaskScheduler.Default); 

मैं छोटे से अनुसंधान किया, परावर्तक का उपयोग कर, यहाँ एक है विधि Task.Run

का स्रोत

विधि Task.Factory.StartNew का महत्वपूर्ण पैरामीटर TaskCreationOptions creationOptions है। विधि Task.Factory.StartNew में पैरामीटर TaskCreationOptions.DenyChildAttach के बराबर है। इसका मतलब यह है कि

एक InvalidOperationException एक प्रयास के लिए किया जाता है, तो बनाया कार्य

आप कोड का सही व्यवहार को प्राप्त करने के TaskCreationOptions.None को बदलने की जरूरत है के लिए एक बच्चे को काम देते फेंक दिया जाएगा।

विधि Task.Runटास्कक्रिएशनऑप्शन पैरामीटर को बदलने की क्षमता प्रदान नहीं करता है।

+0

* DenyChildAttach * वास्तव में समस्या है। जब मैं इस तरह के मूल कार्य को बनाता हूं: 'टास्कफैक्टरी टीएफ = नया टास्क फैक्ट्री (टास्क क्रिएशनऑप्शन। डेनी चाइल्डएटैच, टास्क कंटिन्यूशनऑप्शन नॉन); कार्य parentTask = tf.StartNew (() => {....}); 'मुझे एक ही समस्या मिलती है और जब मैं * टास्क क्रिएशनऑप्शन का उपयोग करता हूं। कोई * यह ठीक काम करता है। –

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