कंसोल ऐप की 'मुख्य' विधि पर 'async' संशोधक निर्दिष्ट नहीं कर सकता


445

मैं asyncसंशोधक के साथ अतुल्यकालिक प्रोग्रामिंग के लिए नया हूँ । मैं यह पता लगाने की कोशिश कर रहा हूं कि यह कैसे सुनिश्चित करें कि Mainकंसोल एप्लिकेशन का मेरा तरीका वास्तव में अतुल्यकालिक रूप से चलता है।

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = bs.GetList();
    }
}

public class Bootstrapper {

    public async Task<List<TvChannel>> GetList()
    {
        GetPrograms pro = new GetPrograms();

        return await pro.DownloadTvChannels();
    }
}

मुझे पता है कि यह "शीर्ष" से अतुल्यकालिक रूप से नहीं चल रहा है। चूंकि विधि asyncपर संशोधक को निर्दिष्ट करना संभव नहीं है Main, मैं mainअसिंक्रोनस के भीतर कोड कैसे चला सकता हूं ?


23
C # 7.1 में ऐसा नहीं है। मुख्य विधियाँ इस प्रकार हो सकती हैं
वासिली सलौनाईव

2
यहाँ C # 7.1 ब्लॉग पोस्ट की घोषणा हैAsync Main शीर्षक वाला अनुभाग देखें ।
स्टाइल

जवाबों:


382

जैसा कि आपने खोजा, वीएस 11 में कंपाइलर एक async Mainविधि को समाप्त कर देगा । यह Async CTP के साथ VS2010 में अनुमत (लेकिन कभी अनुशंसित नहीं) था।

मेरे पास हाल ही में async / प्रतीक्षा और विशेष रूप से अतुल्यकालिक कंसोल कार्यक्रमों के बारे में ब्लॉग पोस्ट हैं । यहाँ परिचय पोस्ट से कुछ पृष्ठभूमि जानकारी है:

यदि "वेटिट" देखता है कि प्रतीक्षा योग्य ने पूरा नहीं किया है, तो यह अतुल्यकालिक रूप से कार्य करता है। यह पूरी होने पर शेष विधि को चलाने के लिए प्रतीक्षा करने योग्य बताता है, और फिर async विधि से लौटता है। प्रतीक्षारत वर्तमान संदर्भ पर भी कब्जा कर लिया जाएगा जब यह शेष विधि को आवारा करने के लिए पारित करता है।

बाद में, जब प्रतीक्षा पूरी हो जाती है, तो यह एस्किंस पद्धति के शेष (कैप्चर किए गए संदर्भ के भीतर) को निष्पादित करेगा।

यहाँ क्यों यह सांत्वना कार्यक्रमों में एक समस्या है एक के साथ async Main:

हमारे इंट्रो पोस्ट से याद रखें कि पूरा होने से पहले एक कॉल करने के लिए एक async विधि वापस आ जाएगी । यह पूरी तरह से यूआई अनुप्रयोगों में काम करता है (विधि सिर्फ यूआई इवेंट लूप में लौटती है) और एएसपी.नेट एप्लिकेशन (विधि थ्रेड से वापस आती है लेकिन अनुरोध को जीवित रखती है)। यह कंसोल प्रोग्राम के लिए इतनी अच्छी तरह से काम नहीं करता है: ओएस में मुख्य रिटर्न - इसलिए आपका प्रोग्राम बाहर निकलता है।

एक समाधान अपने स्वयं के संदर्भ प्रदान करने के लिए है - आपके कंसोल प्रोग्राम के लिए एक "मुख्य लूप" जो कि async- संगत है।

यदि आपके पास Async CTP वाली मशीन है, तो आप My Documents \ Microsoft Visual Studio Async CTP \ Samples (C # परीक्षण) यूनिट परीक्षण \ AsyncTestUtilitiesGeneralThreadAffineContext से उपयोग कर सकते हैं । वैकल्पिक रूप से, आप मेरे Nito.AsyncEx NuGet पैकेज से उपयोग कर सकते हैं ।AsyncContext

यहां एक उदाहरण का उपयोग किया गया है AsyncContext; GeneralThreadAffineContextलगभग समान उपयोग है:

using Nito.AsyncEx;
class Program
{
    static void Main(string[] args)
    {
        AsyncContext.Run(() => MainAsync(args));
    }

    static async void MainAsync(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

वैकल्पिक रूप से, आप केवल मुख्य कंसोल थ्रेड को ब्लॉक कर सकते हैं जब तक कि आपका एसिंक्रोनस काम पूरा नहीं हो जाता है:

class Program
{
    static void Main(string[] args)
    {
        MainAsync(args).GetAwaiter().GetResult();
    }

    static async Task MainAsync(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

के उपयोग पर ध्यान दें GetAwaiter().GetResult(); यह उस AggregateExceptionरैपिंग से बचा जाता है जो आपके उपयोग Wait()या होने पर होता है Result

अद्यतन, 2017-11-30: विज़ुअल स्टूडियो 2017 अपडेट 3 (15.3) के अनुसार, भाषा अब एक समर्थन करती है async Main- जब तक कि यह वापस आती है Taskया Task<T>। तो अब आप यह कर सकते हैं:

class Program
{
    static async Task Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

शब्दार्थ GetAwaiter().GetResult()मुख्य धागे को अवरुद्ध करने की शैली के समान प्रतीत होता है । हालाँकि, अभी तक C # 7.1 के लिए कोई भाषा युक्ति नहीं है, इसलिए यह केवल एक धारणा है।


30
आप एक सरल या का उपयोग कर सकते हैं , और इसके साथ कुछ भी गलत नहीं है। लेकिन ध्यान रखें कि दो महत्वपूर्ण अंतर हैं: 1) सभी निरंतरता मुख्य धागे के बजाय थ्रेड पूल पर चलती हैं, और 2) किसी भी अपवाद को एक में लपेटा जाता है । WaitResultasyncAggregateException
स्टीफन क्लीयर

2
यह (और आपके ब्लॉग पोस्ट) तक यह पता लगाने में एक वास्तविक समस्या थी। यह इस समस्या को हल करने का अब तक का सबसे आसान तरीका है, और आप पैकेज को केवल "इंस्टॉल-पैकेज Nito.Asyncex" के साथ नगेट कंसोल में स्थापित कर सकते हैं और आप कर रहे हैं।
कांस्टेंटाइनके

1
@StephenCleary: तेजी से प्रतिक्रिया के लिए धन्यवाद स्टीफन। मुझे समझ में नहीं आता है कि जब कोई अपवाद फेंक दिया जाता है तो कोई भी डिबगर को तोड़ना नहीं चाहेगा। यदि मैं डिबगिंग कर रहा हूं और एक शून्य संदर्भ अपवाद पर चलता है, तो कोड की आक्रामक रेखा पर सीधे जाना पसंद करता है। वीएस तुल्यकालिक कोड के लिए "आउट ऑफ द बॉक्स" की तरह काम करता है, लेकिन एसिंक्स / वेट के लिए नहीं।
ग्रेग

6
C # 7.1 में अभी एक async मुख्य है, जो आपके शानदार जवाब को जोड़ने के लायक हो सकता है, @StephenCleary github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1// ...
Mafii

3
यदि आपका वीएस 2017 में सी # 7.1 संस्करण का उपयोग कर रहा है, तो मुझे यह सुनिश्चित करने के लिए परियोजना को कॉन्फ़िगर करने की आवश्यकता थी <LangVersion>latest</LangVersion>, जिसे यहां दिखाए गए अनुसार csproj फ़ाइल में जोड़कर भाषा के नवीनतम संस्करण का उपयोग करने के लिए कॉन्फ़िगर किया गया था ।
लियाम

359

आप इसे इस सरल निर्माण के साथ हल कर सकते हैं:

class Program
{
    static void Main(string[] args)
    {
        Task.Run(async () =>
        {
            // Do any async anything you need here without worry
        }).GetAwaiter().GetResult();
    }
}

वह सब कुछ जो आप थ्रेडपूल पर करते हैं, जहां आप इसे चाहते हैं (इसलिए अन्य कार्य जो आप शुरू करते हैं / इंतजार करते हैं, एक थ्रेड को फिर से शुरू करने का प्रयास नहीं करना चाहिए), और कंसोल ऐप को बंद करने से पहले सब कुछ होने तक प्रतीक्षा करें। विशेष छोरों या बाहर के लिए कोई ज़रूरत नहीं है।

संपादित करें: बिना अपवाद के एंड्रयू के समाधान को शामिल करें।


3
यह दृष्टिकोण बहुत स्पष्ट है, लेकिन अपवादों को लपेटता है इसलिए मैं अब बेहतर तरीके से देख रहा हूं।
अबातिश्चेव

2
@abatishchev आपको अपने कोड में कोशिश / कैच का उपयोग करना चाहिए, कम से कम टास्क के अंदर। अधिक दानेदार नहीं होने पर, अपवादों को टास्क में तैरने नहीं देना चाहिए। आप उन चीज़ों के इर्द-गिर्द ट्राई / कैच डालकर रैप अप समस्या से बच सकते हैं, जो विफल हो सकती हैं।
क्रिस मोसचिनी

54
आप की जगह तो Wait()साथ GetAwaiter().GetResult()आप बच सकेंगे AggregateExceptionजब चीजें फेंक आवरण।
एंड्रयू अरनोट

7
यह async mainइस लेखन के रूप में C # 7.1 में पेश किया जा रहा है।
user9993

@ user9993 इस प्रस्ताव के अनुसार , यह बिल्कुल सच नहीं है।
सिंजई

90

आप बाहरी पुस्तकालयों की आवश्यकता के बिना भी ऐसा कर सकते हैं:

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var getListTask = bs.GetList(); // returns the Task<List<TvChannel>>

        Task.WaitAll(getListTask); // block while the task completes

        var list = getListTask.Result;
    }
}

7
ध्यान रखें कि getListTask.Resultएक अवरुद्ध कॉल भी है और इसलिए उपरोक्त कोड बिना लिखा जा सकता है Task.WaitAll(getListTask)
डू

27
इसके अलावा, अगर GetListफेंकता है तो आपको AggregateExceptionवास्तविक अपवाद को निर्धारित करने के लिए इसके अपवादों को पकड़ना होगा और इसके अपवादों पर पूछताछ करनी होगी । हालाँकि, GetAwaiter()आप इसके TaskAwaiterलिए कॉल कर सकते हैं, Taskऔर GetResult()उस पर कॉल कर सकते हैं, अर्थात var list = getListTask.GetAwaiter().GetResult();। जब TaskAwaiter(भी एक अवरुद्ध कॉल) से परिणाम प्राप्त कर रहे हैं, किसी भी अपवाद को फेंक दिया नहीं एक में लपेटा जाएगा AggregateException
do0g

1
.GetAwaiter ()। GetResult का उत्तर मुझे चाहिए था। मैं जो करने का प्रयास कर रहा था, उसके लिए यह पूरी तरह से काम करता है। मैं शायद अन्य स्थानों में भी इसका उपयोग करूंगा।
डेथस्टेलर

78

C # 7.1 में आप एक उचित Async मेन कर पाएंगे । Mainविधि के लिए उपयुक्त हस्ताक्षरों को बढ़ा दिया गया है:

public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);

उदाहरण के लिए आप ऐसा कर सकते हैं:

static async Task Main(string[] args)
{
    Bootstrapper bs = new Bootstrapper();
    var list = await bs.GetList();
}

संकलन के समय, कॉल करने के लिए async प्रविष्टि बिंदु विधि का अनुवाद किया जाएगा GetAwaitor().GetResult()

विवरण: https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main

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

C # 7.1 भाषा सुविधाओं को सक्षम करने के लिए, आपको प्रोजेक्ट पर राइट-क्लिक करना होगा और "गुण" पर क्लिक करना होगा, फिर "बिल्ड" टैब पर जाएं। वहां, नीचे स्थित उन्नत बटन पर क्लिक करें:

यहां छवि विवरण दर्ज करें

भाषा संस्करण ड्रॉप-डाउन मेनू से, "7.1" (या किसी भी उच्च मूल्य) का चयन करें:

यहां छवि विवरण दर्ज करें

डिफ़ॉल्ट "नवीनतम प्रमुख संस्करण" है जो मूल्यांकन करेगा (इस लेखन के समय) C # 7.0 के लिए, जो कंसोल ऐप्स में async मुख्य का समर्थन नहीं करता है।


2
FWIW यह Visual Studio 15.3 और ऊपर में उपलब्ध है, जो वर्तमान में यहाँ से बीटा / प्रीव्यू रिलीज़ के रूप में उपलब्ध है: Visualstudio.com/vs/preview
Mahmoud Al-Qudsi

एक मिनट प्रतीक्षा करें ... मैं पूरी तरह से अद्यतन स्थापित कर रहा हूं और मेरा नवीनतम विकल्प 7.1 है ... आपको मई में पहले से ही 7.2 कैसे मिलेंगे?

मई जवाब मेरा था। अक्टूबर एडिट किसी और द्वारा किया गया था जब तक मुझे लगता है कि 7.2 (पूर्वावलोकन?) जारी हो सकता है।
नवाफल

1
सिर ऊपर - जाँच करें कि यह सब कॉन्फ़िगर पर है, न कि केवल डिबग करें जब आप ऐसा करते हैं!
user230910

1
@ user230910 धन्यवाद सी # टीम द्वारा सबसे अजीब विकल्पों में से एक।
नवाफल

74

मैं एक महत्वपूर्ण विशेषता जोड़ूंगा कि अन्य सभी उत्तरों को अनदेखा कर दिया गया है: रद्द करना।

टीपीएल में एक बड़ी चीज रद्दीकरण समर्थन है, और कंसोल एप्स में रद्दीकरण की एक विधि है (CTRL + C)। उन्हें एक साथ बांधना बहुत सरल है। यह है कि मैं अपने सभी async कंसोल एप्लिकेशन को कैसे संरचना करता हूं:

static void Main(string[] args)
{
    CancellationTokenSource cts = new CancellationTokenSource();

    System.Console.CancelKeyPress += (s, e) =>
    {
        e.Cancel = true;
        cts.Cancel();
    };

    MainAsync(args, cts.Token).Wait();
}

static async Task MainAsync(string[] args, CancellationToken token)
{
    ...
}

क्या कैंसिलेशन टोकन को भी पास किया जाना चाहिए Wait()?
Siewers

5
नहीं, क्योंकि आप चाहते हैं कि एस्कि कोड एक सुंदर तरीके से रद्द करने में सक्षम हो। यदि आप इसे पास करते हैं Wait(), तो यह समाप्त होने के लिए async कोड की प्रतीक्षा नहीं करेगा - यह प्रतीक्षा करना बंद कर देगा और प्रक्रिया को तुरंत समाप्त कर देगा।
कोरी नेल्सन

क्या अापको उस बारे में पूर्ण विशवास है? मैंने अभी इसे आज़माया है, और ऐसा लगता है कि रद्द करने के अनुरोध को सबसे गहरे स्तर पर संसाधित किया जा रहा है, तब भी जब Wait()विधि समान टोकन पारित की जाती है। मैं जो कहना चाह रहा हूं, वह यह है कि इससे कोई फर्क नहीं पड़ता।
20

4
मुझे यकीन है। आप सेशन को रद्द करना चाहते हैं, न कि ऑप के खत्म होने का इंतजार। जब तक आप सफाई कोड परिष्करण या इसके परिणाम के बारे में परवाह नहीं करते हैं।
कोरी नेल्सन

1
हाँ, मुझे लगता है कि मुझे यह मिल गया है, यह सिर्फ मेरे कोड में कोई फर्क नहीं लगता था। एक और बात जिसने मुझे पाठ्यक्रम से बाहर कर दिया, वह था रद्द करने का समर्थन करने वाली प्रतीक्षा पद्धति के बारे में एक विनम्र प्रतिशोधी संकेत;) आप उदाहरण में एक कोशिश पकड़ना शामिल करना चाह सकते हैं, क्योंकि यह एक OperationCancelledException को फेंक देगा, जिसे मैं पहले पता नहीं लगा सका था
Siewers

22

C # 7.1 (2017 बनाम 3 का उपयोग करके) async मुख्य का परिचय देता है

तुम लिख सकते हो:

   static async Task Main(string[] args)
  {
    await ...
  }

अधिक जानकारी के लिए C # 7 Series, भाग 2: Async Main

अपडेट करें:

आपको एक संकलन त्रुटि मिल सकती है:

कार्यक्रम में एक प्रवेश बिंदु के लिए उपयुक्त एक स्थिर 'मुख्य' विधि शामिल नहीं है

यह त्रुटि इस कारण से है कि vs2017.3 डिफ़ॉल्ट रूप से c # 7.0 नहीं c # 7.1 के रूप में कॉन्फ़िगर किया गया है।

आपको c # 7.1 सुविधाओं को सेट करने के लिए अपनी परियोजना की सेटिंग को स्पष्ट रूप से संशोधित करना चाहिए।

आप c # 7.1 को दो तरीकों से सेट कर सकते हैं:

विधि 1: प्रोजेक्ट सेटिंग्स विंडो का उपयोग कर:

  • अपने प्रोजेक्ट की सेटिंग खोलें
  • बिल्ड टैब चुनें
  • उन्नत बटन पर क्लिक करें
  • निम्नांकित आकृति में दिखाए गए संस्करण का चयन करें:

यहां छवि विवरण दर्ज करें

Method2: मैन्युअल रूप से .croroj के PropertyGroup संशोधित करें

यह गुण जोड़ें:

    <LangVersion>7.1</LangVersion>

उदाहरण:

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <PlatformTarget>AnyCPU</PlatformTarget>
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <OutputPath>bin\Debug\</OutputPath>
        <DefineConstants>DEBUG;TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
        <Prefer32Bit>false</Prefer32Bit>
        <LangVersion>7.1</LangVersion>
    </PropertyGroup>    

20

आप सी # 7.1 या का उपयोग कर बाद में कर रहे हैं, के साथ जाने के nawfal के जवाब और बस के लिए अपने मुख्य विधि की वापसी प्रकार बदलने Taskया Task<int>। यदि आप नहीं हैं:

  • लो एक async Task MainAsync जोहन की तरह कहा
  • .GetAwaiter().GetResult()अंतर्निहित अपवाद को पकड़ने के लिए कॉल करें जैसे do0g कहा
  • कोरी की तरह समर्थन रद्द ।
  • एक दूसरे CTRL+Cको तुरंत प्रक्रिया को समाप्त करना चाहिए। (धन्यवाद बिंकी !)
  • हैंडल OperationCancelledException- एक उपयुक्त त्रुटि कोड लौटाएं।

अंतिम कोड इस तरह दिखता है:

private static int Main(string[] args)
{
    var cts = new CancellationTokenSource();
    Console.CancelKeyPress += (s, e) =>
    {
        e.Cancel = !cts.IsCancellationRequested;
        cts.Cancel();
    };

    try
    {
        return MainAsync(args, cts.Token).GetAwaiter().GetResult();
    }
    catch (OperationCanceledException)
    {
        return 1223; // Cancelled.
    }
}

private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
    // Your code...

    return await Task.FromResult(0); // Success.
}

1
कई अच्छे कार्यक्रम रद्द करें रद्द करेंकेवल पहली बार केवल इतना है कि अगर आप एक बार ग्रेसफुल शटडाउन प्राप्त करते हैं, तो सी दबाते हैं, लेकिन अगर आप अधीर हैं तो दूसरा ^ सी अपमानजनक रूप से समाप्त होता है। इस समाधान के साथ, यदि आपको रद्द करने की अनुमति नहीं e.Cancel = trueहै , तो आपको प्रोग्राम को मैन्युअल रूप से मारना होगा क्योंकि यह बिना शर्त है।
binki

19

अभी तक इसकी बहुत आवश्यकता नहीं है, लेकिन जब मैंने त्वरित परीक्षणों के लिए कंसोल एप्लिकेशन का उपयोग किया है और आवश्यक async मैं इसे इस तरह हल किया है:

class Program
{
    static void Main(string[] args)
    {
        MainAsync(args).Wait();
    }

    static async Task MainAsync(string[] args)
    {
        // Code here
    }
}

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

6
सच नहीं, @ManushinIgor कम से कम इस तुच्छ उदाहरण में, SynchronizationContextमुख्य धागे के साथ कोई संबंध नहीं है । तो यह गतिरोध नहीं होगा क्योंकि बिना भी ConfigureAwait(false), सभी निरंतरता थ्रेडपूल पर निष्पादित होगी।
एंड्रयू अरनोट

7

मुख्य से अतुल्यकालिक कॉलिंग कार्य के लिए, का उपयोग करें

  1. .NET 4.5 के लिए Task.Run ()

  2. .NET 4.0 के लिए Task.Factory.StartNew () Microsoft (async और वेटिंग कीवर्ड के लिए Microsoft.Bcl.Async लाइब्रेरी की आवश्यकता हो सकती है)

विवरण: http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx


4

मुख्य में कॉल को गेटलिस्ट में बदलने का प्रयास करें:

Task.Run(() => bs.GetList());

4

जब C # 5 CTP पेश किया गया था, तो आप निश्चित रूप से Main को चिह्नित कर सकते थे async... हालाँकि ऐसा करना आम तौर पर एक अच्छा विचार नहीं था। मेरा मानना ​​है कि यह वीएस 2013 की रिहाई के द्वारा एक त्रुटि बन गई थी।

जब तक आप किसी अन्य अग्रभूमि धागे को शुरू नहीं करते हैं , तब तक आपका कार्यक्रम Mainपूरा होने पर बाहर निकल जाएगा , भले ही वह कुछ पृष्ठभूमि का काम शुरू कर रहा हो।

आप वास्तव में क्या करने की कोशिश कर रहे हैं? ध्यान दें कि आपकी GetList()विधि को वास्तव में इस समय async होने की आवश्यकता नहीं है - यह बिना किसी वास्तविक कारण के एक अतिरिक्त परत जोड़ रहा है। यह तार्किक रूप से (लेकिन उससे अधिक जटिल) के बराबर है:

public Task<List<TvChannel>> GetList()
{
    return new GetPrograms().DownloadTvChannels();
}

2
जॉन, मैं सूची में आइटम को अतुल्यकालिक रूप से प्राप्त करना चाहता हूं, इसलिए उस GetList पद्धति पर async उपयुक्त क्यों नहीं है? क्या यह इसलिए है क्योंकि मुझे सूची में आइटमों को इकट्ठा करने की जरूरत है 'नहीं' और न ही सूची? जब मैं async के साथ मुख्य विधि को चिह्नित करने का प्रयास करता हूं, तो मुझे "एक स्थिर मुख्य विधि शामिल नहीं है ..."
danielovich

@danielovich: क्या DownloadTvChannels()लौटा? संभवत: यह एक रिटर्न Task<List<TvChannel>>यह नहीं है? यदि नहीं, तो इसकी संभावना नहीं है कि आप इसका इंतजार कर पाएंगे। (संभव है, वेटर पैटर्न दिया गया है, लेकिन संभावना नहीं है।) Mainविधि के लिए - यह अभी भी स्थिर होने की आवश्यकता है ... क्या आपने संशोधक को संभवतः संशोधक से बदल दिया है ? staticasync
जॉन स्कीट

हाँ, यह एक टास्क देता है <..> जैसा आपने कहा। कोई फर्क नहीं पड़ता कि मैं कैसे मुख्य विधि हस्ताक्षर में async डालने की कोशिश करता हूँ यह एक त्रुटि फेंकता है। मैं VS11 पूर्वावलोकन बिट्स पर बैठा हूँ!
danielovich

@danielovich: यहां तक ​​कि एक शून्य वापसी प्रकार के साथ? बस public static async void Main() {}? लेकिन अगर DownloadTvChannels()पहले से ही एक रिटर्न Task<List<TvChannel>>, संभवतः यह पहले से ही अतुल्यकालिक है - तो आपको एक और परत जोड़ने की आवश्यकता नहीं है। यह ध्यान से समझने लायक है।
जॉन स्कीट

1
@nawfal: पीछे देखते हुए, मुझे लगता है कि VS2013 जारी होने से पहले यह बदल गया था। यकीन नहीं होता कि C # 7 बदल रहा होगा ...
जॉन स्कीट

4

C # - C # 7.1 का नवीनतम संस्करण async कंसोल ऐप बनाने की अनुमति देता है। C # 7.1 को प्रोजेक्ट में सक्षम करने के लिए, आपको अपने VS को कम से कम 15.3 पर अपग्रेड करना होगा, और C # वर्जन को C# 7.1या में बदलना होगा C# latest minor version। ऐसा करने के लिए, प्रोजेक्ट गुण -> बिल्ड -> उन्नत -> भाषा संस्करण पर जाएं।

इसके बाद, निम्नलिखित कोड काम करेगा:

internal class Program
{
    public static async Task Main(string[] args)
    {
         (...)
    }

3

MSDN पर, Task.Run Method (Action) के लिए प्रलेखन यह उदाहरण प्रदान करता है जो यह बताता है कि किस तरीके से असिंक्रोनस तरीके से चलाएं main:

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
    public static void Main()
    {
        ShowThreadInfo("Application");

        var t = Task.Run(() => ShowThreadInfo("Task") );
        t.Wait();
    }

    static void ShowThreadInfo(String s)
    {
        Console.WriteLine("{0} Thread ID: {1}",
                          s, Thread.CurrentThread.ManagedThreadId);
    }
}
// The example displays the following output:
//       Application thread ID: 1
//       Task thread ID: 3

उदाहरण के बाद इस कथन पर ध्यान दें:

उदाहरण बताते हैं कि अतुल्यकालिक कार्य मुख्य एप्लिकेशन थ्रेड की तुलना में एक अलग थ्रेड पर निष्पादित होता है।

इसलिए, यदि आप कार्य को मुख्य एप्लिकेशन थ्रेड पर चलाना चाहते हैं, तो @StephenCleary द्वारा उत्तर देखें ।

और उस धागे के बारे में, जिस पर कार्य चलता है, स्टीफन की टिप्पणी पर भी ध्यान दें :

आप एक सरल या का उपयोग कर सकते हैं , और इसके साथ कुछ भी गलत नहीं है। लेकिन ध्यान रखें कि दो महत्वपूर्ण अंतर हैं: 1) सभी निरंतरता मुख्य धागे के बजाय थ्रेड पूल पर चलती हैं, और 2) किसी भी अपवाद को एक में लपेटा जाता है ।WaitResultasyncAggregateException

( अपवाद से निपटने के लिए अपवाद हैंडलिंग लाइब्रेरी (टास्क पैरेलल लाइब्रेरी देखें) a से निपटने के लिए अपवाद हैंडलिंग को कैसे शामिल किया जाए AggregateException।)


अंत में, टास्क डेली विधि (टाइमस्पैन) के लिए प्रलेखन से MSDN पर , यह उदाहरण दिखाता है कि एक अतुल्यकालिक कार्य कैसे चलाया जाता है जो एक मान लौटाता है:

using System;
using System.Threading.Tasks;

public class Example
{
    public static void Main()
    {
        var t = Task.Run(async delegate
                {
                    await Task.Delay(TimeSpan.FromSeconds(1.5));
                    return 42;
                });
        t.Wait();
        Console.WriteLine("Task t Status: {0}, Result: {1}",
                          t.Status, t.Result);
    }
}
// The example displays the following output:
//        Task t Status: RanToCompletion, Result: 42

ध्यान दें कि एक पास delegateकरने के Task.Runबजाय, आप इसके बजाय एक लंबो फ़ंक्शन को पास कर सकते हैं:

var t = Task.Run(async () =>
        {
            await Task.Delay(TimeSpan.FromSeconds(1.5));
            return 42;
        });

1

जब आप किसी फ़ंक्शन को कॉल स्टैक के नीचे कहीं कॉल करते हैं, तो ठंड से बचने के लिए, जो वर्तमान थ्रेड को फिर से शामिल करने की कोशिश करता है (जो एक प्रतीक्षा में फंस गया है), आपको निम्न करने की आवश्यकता है:

class Program
{
    static void Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        List<TvChannel> list = Task.Run((Func<Task<List<TvChannel>>>)bs.GetList).Result;
    }
}

(कास्ट केवल अस्पष्टता को हल करने के लिए आवश्यक है)


धन्यवाद; Task.Run GetList के गतिरोध का कारण नहीं बनता है (), रुको, इस उत्तर को और अधिक बढ़ावा मिलता है ...
Stefano d'Antonio

1

मेरे मामले में मेरे पास उन नौकरियों की एक सूची थी जो मैं अपने मुख्य तरीके से एसिंक्स में चलाना चाहता था, काफी समय से उत्पादन में इसका उपयोग कर रहा था और ठीक काम करता है।

static void Main(string[] args)
{
    Task.Run(async () => { await Task.WhenAll(jobslist.Select(nl => RunMulti(nl))); }).GetAwaiter().GetResult();
}
private static async Task RunMulti(List<string> joblist)
{
    await ...
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.