سؤال

لسبب ما هناك توقف مؤقت بعد بدء البرنامج أدناه. أعتقد أن WebClient().DownloadStringTaskAsync() هو السبب.

class Program
{
    static void Main(string[] args)
    {
        AsyncReturnTask();

        for (int i = 0; i < 15; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(100);
        }
    }

    public static async void AsyncReturnTask()
    {
        var result = await DownloadAndReturnTaskStringAsync();
        Console.WriteLine(result);
    }

    private static async Task<string> DownloadAndReturnTaskStringAsync()
    {
        return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));
    }
}

بقدر ما أفهم ، يجب أن يبدأ برنامجي في العد من 0 إلى 15 على الفور. أفعل شيئا خاطئا؟

واجهت نفس المشكلة مع عينة تنزيل Netflix الأصلية (التي تحصل عليها CTP) - بعد الضغط على زر البحث ، يتجمد واجهة المستخدم أولاً - وبعد مرور بعض الوقت ، يستجيب أثناء تحميل الأفلام التالية. وأعتقد أنه لم يتجمد في عرض Anders Hejlsberg في PDC 2010.

شيء اخر. عندما بدلا من

return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));

أنا استخدم طريقتي الخاصة:

return await ReturnOrdinaryTask();

الذي:

public static Task<string> ReturnOrdinaryTask()
{
    var t = Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("------------- " + i.ToString());
            Thread.Sleep(100);
        }
        return "some text";
    });
    return t;
}

وهي تعمل كما يجب. أعني أنه لا يحمل أي شيء ، لكنه يبدأ على الفور ولا يحظر الخيط الرئيسي ، أثناء القيام بعمله.

يحرر

حسنًا ، ما أؤمن به الآن هو: WebClient.DownloadStringTaskAsync الوظيفة مشدودة. يجب أن تعمل بدون فترة الحظر الأولية ، مثل هذا:

    static void Main(string[] args)
    {
        WebClient cli = new WebClient();
        Task.Factory.StartNew(() =>
            {
                cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
                cli.DownloadStringAsync(new Uri("http://www.weather.gov"));
            });

        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(100);
        }
    }
هل كانت مفيدة؟

المحلول

بينما يحظر البرنامج الخاص بك لفترة من الوقت ، فإنه يستأنف التنفيذ في الحلقة ، قبل إرجاع النتيجة من الخادم البعيد.

تذكر أن واجهة برمجة تطبيقات ASYNC الجديدة لا تزال واحدة من الخيوط. لذا WebClient().DownloadStringTaskAsync() لا يزال يتعين على تشغيل موضوعك حتى يتم إعداد الطلب وإرساله إلى الخادم ، قبل أن يتمكن من ذلك await وإعطاء التنفيذ مرة أخرى إلى تدفق البرنامج في Main ().

أعتقد أن النتائج التي تراها بسبب حقيقة أن الأمر يستغرق بعض الوقت لإنشاء وإرسال الطلب من جهازك. أولا عندما ينتهي ذلك ، فإن تنفيذ DownloadStringTaskAsync يمكن أن تنتظر إكمال الشبكة IO والخادم البعيد ، ويمكنه إرجاع التنفيذ لك.

من ناحية أخرى ، RunOrdinaryTask تهيئة الطريقة المهمة فقط وتمنحها عبء عمل ، ويخبرها بالبدء. ثم يعود على الفور. هذا هو السبب في أنك لا ترى تأخيرًا عند الاستخدام RunOrdinaryTask.

فيما يلي بعض الروابط حول هذا الموضوع: مدونة إريك ليبرت (أحد مصممي اللغة) ، وكذلك منشور مدونة جون سكيت الأولي حوله. لدى إريك سلسلة من 5 منشورات حول أسلوب التماس المستمر ، وهو ما هو في الحقيقة ما async و await حقا عن. إذا كنت ترغب في فهم الميزة الجديدة بالتفصيل ، فقد ترغب في قراءة منشورات Eric حول CPS و Async. على أي حال ، يقوم كل من الرابطين أعلاه بعمل جيد في شرح حقيقة مهمة للغاية:

  • غير متزامن! = بالتوازي

بعبارات أخرى، async و await لا تدور خيوط جديدة لك. إنها تتيح لك استئناف تنفيذ التدفق العادي الخاص بك ، عندما تقوم بعملية الحظر - الأوقات التي تجلس فيها وحدة المعالجة المركزية الخاصة بك ولا تفعل شيئًا في برنامج متزامن ، في انتظار إكمال بعض العمليات الخارجية.

يحرر

فقط لتوضيح ما يحدث: DownloadStringTaskAsync إعداد استمرار ، ثم المكالمات WebClient.DownloadStringAsync, ، على نفس الموضوع ، و ومن بعد يعود التنفيذ إلى الكود الخاص بك. لذلك ، فإن وقت الحظر الذي تراه قبل أن تبدأ الحلقة في العد ، هو الوقت الذي تستغرقه DownloadStringAsync لإكمال. إن برنامجك مع Async و انتظار أن يكون ما يعادل البرنامج التالي ، والذي يظهر نفس سلوك البرنامج الخاص بك: كتلة أولية ، ثم يبدأ العد ، وفي مكان ما في الوسط ، ينتهي OP Async وطباعة المحتوى من الرابط المطلوب:

    static void Main(string[] args)
    {
        WebClient cli = new WebClient();
        cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
        cli.DownloadStringAsync(new Uri("http://www.weather.gov")); // Blocks until request has been prepared

        for (int i = 0; i < 15; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(100);
        }
    }

ملاحظة: أنا لست خبيرًا في هذا الموضوع بأي حال من الأحوال ، لذلك قد أكون مخطئًا في بعض النقاط. لا تتردد في تصحيح فهمي للموضوع ، إذا كنت تعتقد أن هذا خطأ - نظرت للتو في عرض PDC ولعبت مع CTP الليلة الماضية.

نصائح أخرى

هل أنت متأكد من أن المشكلة لا تتعلق بإعدادات تكوين الوكيل التي يتم اكتشافها من IE/Registry/في مكان ما بطيء؟

حاول إعداد webclient.proxy = null (أو تحديد الإعدادات في app.config) وينبغي أن تكون فترة "الحظر" في الحد الأدنى.

هل تضغط على F5 أو CTLR+F5 لتشغيله؟ مع F5 ، هناك تأخير لـ VS فقط للبحث عن الرموز الخاصة بـ Asyncctplibrary.dll ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top