c# - ما هي الاختلافات بين استخدام ConfigureAwait(false) و Task.Run؟




.net .net-4.5 (3)

تمت الموافقة على @ Stephen بالإجابة ، إذا استمر التشويش راجع أدناه لقطات الشاشة 1 # بدون ConfigureAwait (خطأ)
انظر أدناه صورة الموضوع الرئيسي محاولة تحديث التسمية

2 # مع ConfigureAwait (خطأ)
انظر أدناه موضوع العمل صورة تحاول تحديث التسمية

أعي أنه من المستحسن استخدام ConfigureAwait(false) في await s في رمز المكتبة بحيث لا يتم تشغيل التعليمة البرمجية التالية في سياق تنفيذ المتصل ، والذي قد يكون مؤشر ترابط واجهة المستخدم. أنا أفهم أيضا أن await Task.Run(CpuBoundWork) ينبغي أن تستخدم بدلا من CpuBoundWork() لنفس السبب.

مثال مع ConfigureAwait

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address).ConfigureAwait(false))
    using (var responseContent = httpResponse.Content)
    using (var contentStream = await responseContent.ReadAsStreamAsync().ConfigureAwait(false))
        return LoadHtmlDocument(contentStream); //CPU-bound
}

مثال مع Task.Run

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address))
        return await Task.Run(async () =>
        {
            using (var responseContent = httpResponse.Content)
            using (var contentStream = await responseContent.ReadAsStreamAsync())
                return LoadHtmlDocument(contentStream); //CPU-bound
        });
}

ما هي الاختلافات بين هذين النهجين؟


عندما تقول Task.Run ، فأنت تقول أن لديك بعض عمل وحدة المعالجة المركزية للقيام بذلك قد يستغرق وقتًا طويلاً ، لذلك يجب أن يتم تشغيله دائمًا على مؤشر ترابط تجمّع مؤشر الترابط.

عندما تقول ConfigureAwait(false) ، فأنت تقول أن باقي طريقة async تلك لا تحتاج إلى السياق الأصلي. ConfigureAwait هو أكثر من تلميح للتحسين؛ لا يعني ذلك دائمًا أنه يتم تشغيل الاستمرارية على مؤشر ترابط التجمع مؤشر ترابط.


كملاحظة جانبية ، في كلتا الحالتين ، لا يزال بإمكان LoadPage() حظر مؤشر ترابط واجهة المستخدم الخاصة بك ، لأنك await client.GetAsync(address) يحتاج إلى وقت لإنشاء مهمة لتمريرها إلى ConfigureAwait(false) . وقد تكون العملية التي تستغرق وقتًا طويلاً قد بدأت بالفعل قبل إرجاع المهمة.

أحد الحلول الممكنة هو استخدام SynchronizationContextRemover من here :

public async Task<HtmlDocument> LoadPage(Uri address)
{
    await new SynchronizationContextRemover();

    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address))
    using (var responseContent = httpResponse.Content)
    using (var contentStream = await responseContent.ReadAsStreamAsync())
        return LoadHtmlDocument(contentStream); //CPU-bound
}






c#-5.0