2015-06-05 7 views
6

मैं एक परियोजना का निर्माण कर रहा हूं और एसिंक का उपयोग कर रहा हूं और विधियों का इंतजार कर रहा हूं। हर कोई कहता है कि एसिंक आवेदन ग्राउंड अप से बनाया गया है, तो क्या आपके पास वास्तव में कोई सिंक विधियां होनी चाहिए? क्या आपको सभी कार्य एक कार्य वापस करना चाहिए ताकि आप असीमित रूप से उपयोग कर सकें?"बहुत ज्यादा" async कब और इंतजार कर रहा है? क्या सभी विधियां कार्य वापस करनी चाहिए?

चलिए एक साधारण उदाहरण लेते हैं, जहां मैं संग्रह में डेटा लोड करने के लिए एसक्यूएल का उपयोग कर रहा हूं, यहां कुछ कोड है।

इस कोड को लोड ExecuteQueryAsync विधि, विधि GetQuery एसक्यूएल निर्माण करती है, लेकिन GetTableColumns कॉलिंग का उपयोग करके एक मेज से डेटा। एक बार जब SQL उत्पन्न होता है और निष्पादित हो जाता है, तो मैं संग्रह के माध्यम से लूप करता हूं और GetDataFromReader पर कॉल करके प्रत्येक ऑब्जेक्ट को पॉप्युलेट करता हूं।

क्या मेरे गैर एसिंक विधियों को एसिंक होना चाहिए? क्या मैं प्रोग्रामिंग के सिंक-तरीके के बारे में सोच रहा हूं और कुछ खो रहा हूं?

public async Task<ICollection<MyObject>> ExecuteQueryAsync(Module module, List<SqlParameter> parameters) 
{ 
    var result = new Collection<MyObject>(); 
    var query = GetQuery(module); 

    using (var conn = new SqlConnection(_context.Database.Connection.ConnectionString)) 
    { 
     await conn.OpenAsync(); 

     using (var cmd = new SqlCommand(query, conn)) 
     { 
      if (parameters != null) 
       cmd.Parameters.AddRange(parameters.ToArray()); 

      using (var dr = await cmd.ExecuteReaderAsync()) 
      { 
       while (await dr.ReadAsync()) 
       { 
        result.Add(GetDataFromReader(module, dr)); 
       } 

      } 
     } 

    } 

    return result; 
} 

public string GetQuery(Module module) 
{ 
    return "SELECT " + string.Join(",", GetTableColumns(module).ToArray()) + " FROM [TableA] "; 
} 

public List<string> GetTableColumns(Module module) 
{ 
    var columnNames = new List<string>(); 

    // get all list fields for the module 
    var fields = (from a in module.Groups.SelectMany(a => a.Fields) select a).ToList(); 

    foreach (var field in fields) 
    { 
     if (field.Type == FieldType.List) { 
      string query = "STUFF("; 
      query += "(SELECT ';' + [Value] FROM [TableB] FOR XML PATH(''))"; 
      query += ", 1, 1, '') AS [" + field.ColumnName + "]"; 

      columnNames.Add(query); 
     } else { 
      columnNames.Add("[" + field.ColumnName + "]"); 
     } 
    } 

    return columnNames; 
} 

public MyObject GetDataFromReader(Module module, IDataReader dataReader) 
{ 
    var entity = new MyObject(); 

    for (var i = 0; i < dataReader.FieldCount; i++) 
    { 
     object value = null; 
     var fieldName = dataReader.GetName(i); 

     if (!dataReader.IsDBNull(i)) 
     { 
      value = dataReader.GetValue(i); 
     } 

     entity[fieldName] = value; 
    } 

    return entity; 
} 
+2

यहां कोई निश्चित अंतिम उत्तर नहीं है, यह सब निर्भर करता है। मुझसे छोटी राय; यदि कोई विधि किसी भी एसिंक्रोनस का उपयोग स्वयं नहीं करती है, तो यह स्वयं कुछ पद्धति को फिट करने के लिए एसिंक नहीं होना चाहिए। –

+0

बस एक मामूली नोट। मुझे कॉलस्टैक और संबंधित टूल्स का उपयोग डीबग करने के लिए करना पसंद है, और मैं इसके लिए आपको नफरत करता हूं। Async/Await काफी जटिल वास्तविक कोड पर आसान वाक्यविन्यास है, जो आपको किसी बिंदु पर काट सकता है। –

+2

आपने "async सभी तरह से" के विचार को गलत समझा - यह आपके पूरे async * कॉल पदानुक्रम * async होने के बारे में है। यही है, अगर आप एसिंक्रोनस विधि को कॉल करते हैं, तो आपको स्वयं एसिंक होना चाहिए, और आपके कॉलर और उसके कॉलर इत्यादि भी चाहिए। लेकिन 'string.JoinAsync' या ऐसा कुछ कोड करने का कोई कारण नहीं है - असल में, यह काफी काउंटर- उत्पादक। यदि आप सिंक्रोनस विधियों को केवल कॉल कर रहे हैं, तो आपको * एसिंक नहीं होना चाहिए - यह सिर्फ भ्रामक है। – Luaan

उत्तर

4

एक विधि नहीं async संचालन यह async बनाने में इसके अंदर कोई लाभ है है। आपके पास केवल async विधियां होनी चाहिए जहां आपके पास async ऑपरेशन (I/O, DB, आदि) हो।

यदि आपके एप्लिकेशन में इनमें से बहुत से I/O विधियां हैं और वे आपके कोड बेस में फैले हैं, तो यह एक बुरी बात नहीं है। लेकिन सिंक्रोनस विधियों पर async कीवर्ड न जोड़ें।

आपके विशिष्ट मामले में ExecuteQueryAsync लाभ एसिंक होने के कारण यह await cmd.ExecuteReaderAsync() का उपयोग करने की अनुमति देता है। GetTableColumns और GetDataFromReader सीपीयू गहन तरीकों के रूप में प्रतीत होते हैं और वे फिट नहीं हैं वे async-paraitig इंतजार कर रहे हैं।

7

"के पीछे दर्शन सभी async" non-blocking I/O को सुविधाजनक बनाने के लिए है।

यही है, आपका मुख्य रूप से एसिंक कोड संभावित रूप से पर्यावरण को प्राथमिकता दे सकता है कि आपका एप्लिकेशन या सेवा कैसे निष्पादित की जा रही है और बहु-थ्रेडेड, बहु-प्रक्रिया प्रणाली में जितना संभव हो उतना समांतर निष्पादन प्राप्त कर सकता है।

उदाहरण के लिए, ASP.NET वेब एपीआई, ASP.NET MVC या यहाँ तक कि ASP.NET वेब प्रपत्र (कोड-पीछे) का लाभ सभी async ले अन्य उपयोगकर्ताओं पर वेब अनुरोधों में भाग लेने जबकि कुछ async ऑपरेशन है जारी रखने के लिए कर सकते हैं निष्पादित किया जा रहा है। इस प्रकार, यहां तक ​​कि जब आईआईएस या कटाना जैसे वेब सर्वर समवर्ती अनुरोधों की संख्या को सीमित कर सकते हैं, तो एसिंक ऑपरेशन अनुरोध थ्रेड से अलग थ्रेड में निष्पादित किए जाते हैं, और यह वेब सर्वर को अन्य अनुरोधों का जवाब देने की अनुमति देता है जबकि एसिंक ऑपरेशंस परिणाम प्राप्त करता है और उन्हें जारी रखने की आवश्यकता है:

// While WhateverAsync is being executed, current thread can be used 
// by a new request and so on. 
// Obviously, this will work this way if WhateverAsync actually 
// does its work in another thread... 
await WhateverAsync(); 

तो ... क्या आपको सबकुछ असंकालिक रूप से लागू करने की आवश्यकता है? यहां तक ​​कि जब आप एक Task लौट आप एक अतुल्यकालिक कार्यान्वयन प्रदान करने की आवश्यकता नहीं है:

public Task WhateverAsync() 
{ 
    // This creates a fake Task object which 
    // simulates a Task that has already ended successfully 
    // and without creating a child thread! 
    // This, this method is a SYNCHRONOUS implementation unless 
    // the whole method doesn't execute asynchronous operations. 
    return Task.FromResult(true); 
} 

मेरे दृष्टिकोण यहाँ है ...

  • ... सब कुछ एक टास्क लौटने और का उपयोग कर लागू विधि के पहचानकर्ताओं के अंत में Async प्रत्यय (WhateverAsync, WhoKnowsAsync, DoStuffAsync ...) ...

  • ... जब तक कि आप यह सुनिश्चित नहीं कर सकते कि पूरी विधि हमेशा एक बहुत ही सरल चीजें निष्पादित करेगी जो एप्लिकेशन/सेवा के थ्रेड को लंबे समय तक अवरुद्ध नहीं कर सकती है (लंबे समय तक कुछ मिलीसेकंड हो सकते हैं, अब एक कोड की कल्पना करें जब भी कुछ विधि कहा जाता है तो 100 एमएम के लिए मुख्य ऐप थ्रेड को अवरुद्ध नहीं करता है और 100ms का इंतजार कर रहा है, तो आपका कोड कुछ निष्पादित करने से पहले प्राथमिकता दे सकता है ....)। मैं यहाँ स्ट्रिंग परिवर्तन, सरल अंकगणितीय आपरेशनों, विन्यास तरीकों ...

अपने कोड आज async नहीं है, तो आप इसे वास्तविक async संचालन में संपूर्ण कोड आधार को प्रभावित किए बिना, के रूप में केवल आप बदल सकते हैं शामिल होंगे Task.FromResult<T>(T result) कॉल को बदलने की आवश्यकता है वास्तव में एक अधूरा Task उदाहरण वापस करने के लिए कॉल करें।

दिन के अंत में, आपके तरीकों में एसिंक हस्ताक्षर और निर्भरताएं हैं, परवाह नहीं है कि वे वास्तव में असीमित हैं या नहीं, और इन विधि कार्यान्वयन का निर्णय यह है कि कॉलर को यह ज़िम्मेदारी देने के बजाय असीमित या तुल्यकालिक क्या है ।

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