async और प्रतीक्षा - विकल्प के लिए सर्वेक्षण [बंद]


15

अब हम जानते हैं कि क्या # 5 ग के लिए दुकान में है, वहाँ जाहिरा तौर पर अभी भी हम 'के लिए दो नए कीवर्ड की पसंद को प्रभावित करने के लिए के लिए एक प्रारंभिक है Asynchrony ' है कि कम से कल ऐन्डर्स Heijsberg द्वारा घोषणा की गई PDC10

async void ArchiveDocuments(List<Url> urls) {
    Task archive = null;
    for(int i = 0; i < urls.Count; ++i) {
        var document = await FetchAsync(urls[i]);
        if (archive != null)
            await archive;
        archive = ArchiveAsync(document);
    }
}

एरिक लिपर्ट के पास वर्तमान दो कीवर्ड की पसंद का स्पष्टीकरण है, और जिस तरह से उन्हें प्रयोज्य अध्ययन में गलत समझा गया है। टिप्पणियों में कई अन्य प्रस्ताव हैं।

कृपया - प्रति उत्तर एक सुझाव, डुप्लिकेट को nuked किया जाएगा।


जिस तरह से "भाषा-एकीकृत अतुल्यकालिक प्रोग्रामिंग" हमें LIAP देता है, जीभ को LINQ के समान ही रोल नहीं करता है;)
बेंजोल

1
जब तक इसकी स्पष्ट छलांग नहीं लगती।
कॉनराड फ्रैक्स

3
लेकिन "भाषा-एकीकृत अतुल्यकालिक रनटाइम" अच्छी तरह से जोड़ते हैं।
ग्लेनट्रॉन

यह ऑफ-टॉपिक हो गया है।
डेडएमजी

जवाबों:


6

यह देखते हुए कि मैं के अर्थ / आवश्यकता के बारे में स्पष्ट नहीं हूं async, मैं वास्तव में इसके साथ बहस नहीं कर सकता, लेकिन जगह के लिए मेरा सबसे अच्छा सुझाव awaitहै:

yield while (देखो! कोई नया कीवर्ड नहीं)

ध्यान दें कि इस बारे में थोड़ा और सोचा है, मुझे आश्चर्य है कि क्या whileइस तरह से फिर से उपयोग करना एक अच्छा विचार है - स्वाभाविक प्रवृत्ति बाद में एक बूलियन की उम्मीद करना होगा।

(सोचता है: अच्छे कीवर्ड ढूंढना अच्छा डोमेन नाम खोजने जैसा है :)


+1 और वैसे भी, आपने मुझे उनके ब्लॉग प्रविष्टि पर टिप्पणी करने के लिए 7 मिनट तक हरा दिया ...
स्वयं पर ध्यान दें - एक नाम के बारे में सोचें

लेकिन यदि आप कार्य पहले ही पूरा कर चुके हैं तो आपको निष्पादन की आवश्यकता नहीं है। लेकिन आप हमेशा कार्य पूरा होने की प्रतीक्षा कर रहे हैं (हालांकि कभी प्रतीक्षा नहीं की गई)।
एलन ग्रेल्नक

@ सभी आवश्यक नहीं है कि while(x) {...}यदि xआप गलत हैं तो लूप बॉडी को चलाएं ।
स्व पर ध्यान दें -

@ नोट: वैसे इसमें कोई क्रिया नहीं है while। यदि आप एक क्रिया को जोड़ते हैं, जैसे do, तो आप प्राप्त करते हैं do {...} while (x), जो शरीर को एक्स की परवाह किए बिना निष्पादित करता है (कम से कम एक बार)। आपका सुझाव yield whileबहुत हद तक समान लगता है do while, लेकिन क्रिया प्रदर्शन के विपरीत गारंटी के साथ, जो थोड़ा भ्रामक हो सकता है (लेकिन यह बहुत बड़ी बात नहीं है)। जिस चीज के बारे में मुझे सबसे ज्यादा नापसंद yieldहै वह यह है कि यह एक तंत्र के कार्यान्वयन का अर्थ है। async/ की पूरी बात awaitयह है कि आप एक एसिंक्रोनस ऑपरेशन को समकालिक शैली में लिखते हैं। yieldउस तुल्यकालिक शैली को तोड़ता है।
एलोन गुरिलनेक

क्या एक नया कीवर्ड जरूरी एक बुरी चीज है? जैसा कि मैं इसे समझता हूं, awaitकीवर्ड को संदर्भ से पहचाना जाएगा, इसलिए यदि आप चाहते हैं तो भी आपके पास "प्रतीक्षा" नामक एक विधि या चर हो सकता है। कुछ हद तक, मुझे लगता है कि नई कार्यक्षमता के लिए नए कीवर्ड का उपयोग करना मौजूदा कीवर्ड को एक से अधिक चीजों के लिए उपयोग करने से कम भ्रमित नहीं करता है। (अतिरंजित उदाहरण: dangermouse.net/esoteric/ook.html )
टिम गुडमैन

5

कैसे एक खोजशब्द के बारे में नहीं है?

मैं संकलक को यह महसूस करना चाहता हूं कि, ज्यादातर समय, जब मैं एक अतुल्यकालिक विधि कहता हूं, तो मुझे इसका परिणाम चाहिए।

Document doc = DownloadDocumentAsync();

बस। लोगों को इस चीज़ के लिए एक कीवर्ड के बारे में सोचने में एक कठिन समय हो रहा है, क्योंकि यह एक कीवर्ड के लिए है "जैसे कि अगर आप पूरी तरह से सामान्य थे तो वह काम करेंगे जो आप करते हैं"। यह डिफ़ॉल्ट होना चाहिए, एक कीवर्ड की आवश्यकता नहीं है।

अपडेट करें

मैंने मूल रूप से सुझाव दिया कि संकलक को यह पता लगाने के लिए कि क्या करना है के प्रकार के साथ चतुर होना चाहिए। इसके बारे में और सोचने के बाद, मैं मौजूदा कार्यान्वयन को CTP में यथावत रखता हूँ, लेकिन इसमें कुछ जोड़-घटाव करते हैं, ताकि उन मामलों को कम किया जा सके जहाँ आपको awaitकीवर्ड का स्पष्ट रूप से उपयोग करने की आवश्यकता होगी ।

हम एक विशेषता का आविष्कार करते हैं [AutoAwait]:। यह केवल विधियों पर लागू किया जा सकता है। इसे अपनी विधि पर लागू करने का एक तरीका यह है कि आप इसे चिह्नित करें async। लेकिन आप इसे हाथ से भी कर सकते हैं, जैसे:

[AutoAwait]
public Task<Document> DownloadDocumentAsync()

फिर किसी भी asyncविधि के अंदर , कंपाइलर मान जाएगा कि आप कॉल का इंतजार करना चाहते हैं DownloadDocumentAsync, इसलिए आपको इसे निर्दिष्ट करने की आवश्यकता नहीं है। उस पद्धति का कोई भी कॉल स्वचालित रूप से इसकी प्रतीक्षा करेगा।

Document doc = DownloadDocumentAsync();

अब, यदि आप "चतुर होना चाहते हैं" और प्राप्त करते हैं Task<Document>, तो आप एक ऑपरेटर का उपयोग करते हैं start, जो केवल एक विधि कॉल से पहले दिखाई दे सकता है:

Task<Document> task = start DownloadDocumentAsync();

नीट, मुझे लगता है। अब एक सादे विधि कॉल का अर्थ है कि इसका आम तौर पर क्या मतलब है: विधि के पूरा होने की प्रतीक्षा करें। और startकुछ अलग इंगित करता है: रुको मत।

किसी asyncविधि के बाहर दिखाई देने वाले कोड के लिए , आपको जिस [AutoAwait]विधि से कॉल करने की अनुमति दी जाती है, वह केवल उसी के साथ उपसर्ग करके होती है start। यह आपको ऐसा कोड लिखने के लिए मजबूर करता है जिसका एक ही अर्थ है चाहे वह किसी asyncविधि में दिखाई दे या नहीं।

फिर मुझे लालच आने लगता है! :)

सबसे पहले, मैं asyncइंटरफ़ेस विधियों पर लागू करना चाहता हूं :

interface IThing
{
    async int GetCount();
} 

इसका मूल रूप से यह अर्थ है कि कार्यान्वयन विधि को वापस लौटना चाहिए Task<int>या कुछ संगत होना चाहिए await, और विधि से कॉल करने वालों को [AutoAwait]व्यवहार मिलेगा ।

इसके अलावा जब मैं उपरोक्त विधि को लागू करता हूं, मैं लिखना चाहता हूं:

async int GetCount()

इसलिए मुझे Task<int>रिटर्न प्रकार के रूप में उल्लेख नहीं करना है ।

इसके अलावा, मैं asyncप्रतिनिधि प्रकारों पर आवेदन करना चाहता हूं (जो, आखिरकार, एक विधि के साथ इंटरफेस की तरह हैं)। इसलिए:

public async delegate TResult AsyncFunc<TResult>();

एक asyncप्रतिनिधि के पास है - आपने यह अनुमान लगाया - [AutoAwait]व्यवहार। एक asyncविधि से आप इसे कॉल कर सकते हैं और यह स्वचालित रूप से awaitएड हो जाएगा (जब तक कि आप startइसे नहीं चुनते )। और इसलिए यदि आप कहते हैं:

AsyncFunc<Document> getDoc = DownloadDocumentAsync;

वह सिर्फ काम करता है। यह एक विधि कॉल नहीं है। अभी तक कोई कार्य शुरू नहीं किया गया है - async delegateएक कार्य नहीं है। यह कार्य करने के लिए एक कारखाना है। तुम कह सकते हो:

Document doc = getDoc();

और वह एक कार्य शुरू करेगा और इसे समाप्त करने के लिए प्रतीक्षा करेगा और आपको परिणाम देगा। या आप कह सकते हैं:

Task<Document> t = start getDoc();

तो इसमें एक जगह जहां "प्लंबिंग" लीक है वह यह है कि अगर आप किसी asyncविधि को एक प्रतिनिधि बनाना चाहते हैं , तो आपको एक async delegateप्रकार का उपयोग करने के लिए जानना होगा । तो इसके बजाय Funcआपको कहना चाहिए AsyncFunc, और इसी तरह। हालांकि एक दिन उस प्रकार की चीज को बेहतर प्रकार के अनुमान से तय किया जा सकता है।

एक और सवाल यह है कि यदि आप कहते हैं कि एक साधारण (गैर-एएसक्यूएन) पद्धति पर शुरू होना चाहिए तो क्या होना चाहिए। जाहिर है एक संकलन त्रुटि सुरक्षित विकल्प होगा। लेकिन अन्य संभावनाएं हैं।


यह एक अंतर्निहित रूपांतरण के साथ संभव हो सकता है, लेकिन अन्यथा कथन के बाएं से दाएं मूल्यांकन की आवश्यकता होगी (जो संकलक सामान्य रूप से कैसे काम करता है, लंबोदर को छोड़कर)। मुझे लगता है कि मैं अभी भी इसके खिलाफ हूं क्योंकि यह उपयोग को रोकता है var, संभवतः कुछ लंबे स्पष्ट प्रकार के नाम को स्थानापन्न करने के लिए, और awaitमामले और मामले के बीच अस्पष्ट भी है जहां किसी ने गलती से सामान्य तुल्यकालिक विधि के बजाय async विधि कहा है। यह पहली बार में सहज लगता है लेकिन वास्तव में कम से कम आश्चर्य के सिद्धांत का उल्लंघन करता है।
हारून

@ चेतावनी - इसका उपयोग क्यों रोका जाता है var? मुझे आश्चर्य है कि यदि आप मेरे उत्तर के पिछले संशोधन का जवाब दे रहे हैं ... मैंने इसे पूरी तरह से फिर से लिखा है। अब आप इस सुझाव के बारे में इस प्रकार सोच सकते हैं: यदि विधि एक विशेष विशेषता के साथ चिह्नित है, तो यह ऐसा है जैसे कि awaitकीवर्ड स्वचालित रूप से उस पद्धति पर कॉल के सामने डाला जाता है (जब तक कि आप startउपसर्ग के साथ इसे दबा नहीं देते हैं )। सब कुछ CTP की तरह ही रहता है, और इसलिए varठीक काम करता है।
डैनियल इयरविकेर

वास्तव में मैं ... अजीब था कि मैंने इस धागे को फिर से देखने का फैसला किया और आपके जवाब का लगभग उसी समय जवाब दिया, जिस दिन आपने इसे संपादित करने का फैसला किया था। मैं अब यह पुन: पढ़ने करना होगा ...
Aaronaught

1
मुझे प्रतीक्षित खोजशब्द का आपका उलटा पसंद है। और मैं ट्रिपल-अतिरेक को भी नापसंद करता हूं public async Task<int> FooAsync()
एलन ग्रेलनेक

1
हां, मैं देखता हूं कि Async-postfix नामकरण सम्मेलन एक संकेत के रूप में है कि कुछ को और अधिक औपचारिक रूप से कैप्चर किया जा सकता है। असल में, अगर कोई नियम कहता है कि "इस तरह के तरीकों को एक निश्चित तरीके का नाम दिया जाना चाहिए, तो लोग जानते हैं कि उन्हें कैसे ठीक से कॉल करना है" तो यह इस प्रकार है कि उसी नियम का उपयोग उन तरीकों को एक निश्चित तरीके से करने के लिए किया जा सकता है, और फिर कंपाइलर का उपयोग किया जा सकता है। आप उन्हें ठीक से कॉल करने में मदद करें।
डैनियल इयरविकर

4
hearken unto AsyncFetch(…)

(यदि आप इसे प्राप्त नहीं करते हैं, तो एरिक के ब्लॉग प्रविष्टि को पढ़ें । कम से कम यह बेहतर है for sooth Romeo wherefore art thou AsyncFetch(…))


(उन लोगों की भावना के बिना जिन्हें लागू करने की आवश्यकता नहीं है)
स्वयं पर ध्यान दें -

4

मुझे लगता asyncहै कि यह ठीक है, लेकिन शायद इसलिए कि मैं इसे ASP.NET async पृष्ठों के साथ जोड़ता हूं - वही विचार।

awaitमेरे द्वारा पसंद किए जाने वाले कीवर्ड के लिए continue afterया resume after

मुझे या इसके किसी भी प्रकार को पसंद नहीं हैyield , क्योंकि शब्दार्थ ऐसे हैं कि विधि वास्तव में कभी भी निष्पादन नहीं कर सकती है; यह कार्य की स्थिति पर निर्भर करता है।


मुझे पसंद resume afterहै await। शायद asyncबुलाया जा सकता है resumable
टिम गुडमैन

हालांकि मैं सिर्फ पसंद करूंगा after, continue afterदृष्टिकोण का एक मजबूत कार्यान्वयन लाभ है: इसमें वर्तमान में प्रासंगिक संदर्भ कीवर्ड शामिल है, लेकिन एक सिंटैक्स के साथ जो वर्तमान उपयोग के साथ संगत नहीं है। यह गारंटी देता है कि जोड़ मौजूदा कोड को कभी नहीं तोड़ेगा। पूरी तरह से नए कीवर्ड का उपयोग करते समय, कार्यान्वयन को पुराने कोड पर पहचानकर्ता के रूप में शब्द के संभावित उपयोग से सामना करना पड़ता है, जो काफी मुश्किल हो सकता है।
एडर्न पास्कुअल

3

मैंने एरिक के ब्लॉग पर भी टिप्पणियाँ जोड़ीं, मैं एक ही कीवर्ड का उपयोग करने के साथ कोई समस्या नहीं देखता हूं async

var data = async DownloadFileAsync(url);

मैं सिर्फ यह व्यक्त कर रहा हूं कि मैं फाइल को अतुल्यकालिक रूप से डाउनलोड करना चाहता हूं। यहां थोड़ी सी अतिरेक है, "एसिंक्स" दो बार दिखाई देता है, क्योंकि यह विधि नाम में भी है। कंपाइलर अतिरिक्त चतुर हो सकता है और उस कन्वेंशन का पता लगा सकता है जो "Async" में समाप्त होने वाली विधियाँ, async विधियाँ हैं, और संकलित कोड में हमारे लिए जोड़ें। तो इसके बजाय आप सिर्फ कॉल करना चाहते हैं

var data = async DownloadFile(url);

के रूप में तुल्यकालिक एक कॉल करने के लिए विरोध किया

var data = DownloadFile(url);

हेक, हमें उन्हें उसी तरह से परिभाषित करने में सक्षम होना चाहिए, क्योंकि हमारे घोषणा में async कीवर्ड है, इसलिए हमें प्रत्येक विधि के नाम में मैन्युअल रूप से "Async" जोड़ना चाहिए - कंपाइलर हमारे लिए यह कर सकता है।


मुझे आपके द्वारा जोड़ी गई चीनी पसंद है, हालांकि सी # लोग शायद इसके लिए नहीं जाएंगे। (एफडब्ल्यूआईडब्ल्यू, वे पहले से ही कुछ ऐसा ही करते हैं जब विशेषता नामों की खोज की जाती है)
स्वयं पर ध्यान दें -

2
और यह देखते हुए कि asyncविधि पर कीवर्ड सिर्फ एक अच्छा है (यदि मुझे सही ढंग से समझ में आया है), मुझे आश्चर्य है कि क्या सबसे अच्छी बात यह है कि आप जो भी सुझाव देते हैं उसके विपरीत नहीं होगा: asyncविधि पर छोड़ दें , और बस इसका उपयोग करें वर्तमान में उनके पास कहां है await
बेंजोल

यह एक व्यवसायिकता है। विधि विलोपन पर async कीवर्ड वास्तव में स्वच्छता के लिए ही है। मैं इसे वहां रखना पसंद करूंगा, लेकिन विधि के नाम के लिए "Async" जोड़ने की आवश्यकता के बिना। उदाहरण के async Task<Byte[]> DownloadFile(...)बजाय Task<Byte[]> DownloadFileAsync(...)(उत्तरार्द्ध संकलित हस्ताक्षर वैसे भी हो जाएगा)। किसी भी तरह से काम करता है।
मार्क एच।

मैं ईमानदारी से इसका प्रशंसक नहीं हूं। पिछली टिप्पणी के अनुसार मुझे यह बताना होगा कि आपका अंतिम संस्करण कम से कम आश्चर्य के सिद्धांत का उल्लंघन करता है, क्योंकि यह वास्तव में एक लिखित से पूरी तरह से अलग विधि का आह्वान कर रहा है, और उस पद्धति का कार्यान्वयन और हस्ताक्षर पूरी तरह से कार्यान्वयन वर्ग तक है । यहां तक ​​कि पहला संस्करण समस्याग्रस्त है क्योंकि यह वास्तव में कुछ भी नहीं कह रहा है (अतुल्यकालिक रूप से इस अतुल्यकालिक विधि को निष्पादित करें?)। हम जिस विचार को व्यक्त करने का प्रयास कर रहे हैं वह निरंतरता या आस्थगित निष्पादन है और यह बिल्कुल भी व्यक्त नहीं करता है।
Aaronaught

3

async = कार्य - यह किसी कार्य को वापस करने के लिए एक फ़ंक्शन को संशोधित कर रहा है, इसलिए कीवर्ड "कार्य" का उपयोग क्यों न करें?

प्रतीक्षा करना = समाप्त करना - हमें प्रतीक्षा करने की आवश्यकता नहीं है, लेकिन परिणाम का उपयोग करने से पहले कार्य को "समाप्त" करना है।


यहाँ सरलता के साथ बहस करना वास्तव में कठिन है।
sblom

2

मुझे पसंद है yield untilyield while, पहले से ही सुझाया गया, बहुत अच्छा है और किसी भी नए कीवर्ड को पेश नहीं करता है, लेकिन मुझे लगता है कि "जब तक व्यवहार थोड़ा बेहतर होता है"।

मुझे लगता yield <something>है कि एक महान विचार है, क्योंकि उपज पहले से ही बाकी विधि को एक निरंतरता बनाने के विचार को अच्छी तरह से पकड़ लेती है। शायद कोई "जब तक" से बेहतर शब्द के बारे में सोच सकता है।


2

मैं सिर्फ हारून जी के सुझाव के लिए अपना वोट दर्ज करना चाहता हूं comefrom- पहला उपयुक्त उपयोग जो मैंने INTERCAL के COMEFROM बयान से देखा है। विचार यह है कि यह GOTO ( GOTO स्टेटमेंट से दूर कूदना ) के विपरीत है , जिसमें यह COMEFROM स्टेटमेंट के लिए आपके कोड जंप में कुछ जगह बनाता है ।


2

चूँकि हम Task<T>s के साथ काम कर रहे हैं , इस बारे में startकि कथन से पहले एक खोजशब्द के रूप में उपयोग कैसे किया जाता है:

start var document = FetchAsync(urls[i]);


हम्म, शायद finishइससे भी बेहतर होगा start?
नायक

1

यह ध्यान देने योग्य है कि F # का भी उपयोग करता है async अपने async वर्कफ़्लो में कीवर्ड , जो कि C # 5 में नए async कार्यक्षमता के समान सटीक एक ही चीज़ है। इसलिए, मैं वही रखूंगा

awaitF # में कीवर्ड के लिए , वे सिर्फ let!इसके बजाय उपयोग करते हैं let। C # में समान असाइनमेंट सिंटैक्स नहीं है, इसलिए उन्हें =साइन के दाईं ओर कुछ चाहिए । जैसा कि बेंजोल ने कहा, यह एक ही कार्य करता है, yieldइसलिए यह लगभग उसी का एक प्रकार होना चाहिए।


1
एक "प्रतीक्षा" की आवश्यकता एक असाइनमेंट में बिल्कुल नहीं होती है (हालांकि आमतौर पर यह होता है।) यह बहुत ही किसी भी अभिव्यक्ति पर एक ऑपरेटर के रूप में कानूनी है जिसमें एक प्रकार है जिस पर हम गेटवाटर पा सकते हैं। (सटीक नियमों को अभी तक युवा रूप में काम नहीं किया गया है।)
एरिक लिपिपर्ट

1
@ एरिक, एफ # में वह होगा do!, लेकिन आप जानते हैं कि ...
बेंजोल

1

yield async FetchAsync(..)


यह उस asyncसंशोधक के साथ पूरी तरह से चला जाता है जिसे आपको उस विधि पर लगाने की आवश्यकता होती है जिसे आप लागू कर रहे हैं। और वर्तमान का शब्दार्थ भी yield returnयही है कि आप लौटते हैं और एन्यूमरेटिंग कोड को क्रियान्वित करते हैं जबकि इस मामले में आप अपने निष्पादन को एसिंक्रोनस विधि में ला रहे हैं।

कल्पना कीजिए कि अगर भविष्य में इसके लिए अन्य उपयोग होंगे yield, तो हम यह जोड़ सकते हैं कि yield xजहां x एक चमकदार नई सुविधा है, इन सभी अलग-अलग खोजशब्दों को अधिकतर एक ही काम करने के बजाय, उपज निष्पादन।

सच कहूँ तो, मैं 'नहीं उपज निष्पादन' तर्क को काफी समझते हैं। सब के बाद, एक अन्य विधि को कॉल करने का बिंदु पहले से ही उस पद्धति के लिए 'उपज निष्पादन' नहीं है? फिर चाहे वह अतुल्यकालिक हो या न हो? क्या मुझे यहाँ कुछ याद आ रहा है?

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

IMO मुझे लगता है कि विभिन्न 'न उपजने वाले' मामले एक कार्यान्वयन विवरण हैं। मैं भाषा में स्थिरता के लिए (अर्थात पुन: उपयोग yield) करना चाहता हूँ।


0

कैसे के बारे में complete, जैसा कि "मैं चाहता हूं कि कार्य पूरा हो जाए"?

Task<byte[]> downloadTask = DownloadFileAsync(url);
byte[] data = complete downloadTask;

1
क्यों होता है पतन? यह एक शिष्टाचार है कि कम से कम अपने आप को नीचा दिखाने के बाद समझाएं।
बजे एलन गुरेलनेक

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.