سؤال

يمكن لأي شخص أن يشرح ما await وظيفة لا؟

هل كانت مفيدة؟

المحلول

انهم فقط تحدث عن هذا في PDC في الامس!

يستخدم الانتظار بالتزامن مع المهام (البرمجة الموازية) في .NET. إنها كلمة رئيسية يتم تقديمها في الإصدار التالي من .NET. يتيح لك "إيقاف" تنفيذ طريقة ما إلى حد ما لانتظار المهمة لإكمال التنفيذ. إليك مثال موجز:

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running  
ShowLoaderControl();  
StartStoryboard();

//this will actually "pause" the code execution until the task completes.  It doesn't lock the thread, but rather waits for the result, similar to an async callback  
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed  
listBoxControl.DataContext = table;  
StopStoryboard();  
HideLoaderControl();

نصائح أخرى

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

فكر في الأمر على أنه يشبه إلى حد ما أ yield return بيان في طريقة تنتج ienumerable. عندما يضرب وقت التشغيل yield, ، سيوفر بشكل أساسي الحالة الحالية للطريقة ، وإرجاع القيمة أو المرجع الذي يتم إنتاجه. في المرة التالية التي يتم فيها استدعاء ienumerator.movenext () على كائن الإرجاع (الذي يتم إنشاؤه داخليًا بواسطة وقت التشغيل) ، تتم استعادة الحالة القديمة للطريقة إلى المكدس وتستمر التنفيذ مع السطر التالي بعد yield return كما لو أننا لم نترك هذه الطريقة. بدون هذه الكلمة الرئيسية ، يجب أن يكون نوع Ienumerator محددًا خصيصًا لتخزين الحالة والتعامل مع طلبات التكرار ، مع الطرق التي يمكن أن تصبح معقدة للغاية بالفعل.

وبالمثل ، فإن الطريقة التي تحمل علامة async يجب أن يكون لديك واحد على الأقل await. على await, ، سيحفظ وقت التشغيل حالة مؤشر الترابط الحالي ومكدس الاتصال ، وإجراء المكالمة غير المتزامنة ، والاسترخاء إلى حلقة رسالة وقت التشغيل للتعامل مع الرسالة التالية والحفاظ على استجابة التطبيق. عند اكتمال العملية غير المتزامنة ، يتم دفع مكدس المكالمة لارتفاع عملية الاستدعاء إلى ما بعد أن كانت المكالمة متزامنة.

لذلك ، فإن هاتين الكلمة الرئيسية الجديدة تبسيط بشكل أساسي ترميز العمليات غير المتزامنة ، مثلما يشبه إلى حد كبير yield return تبسيط توليد العدوى المخصصة. مع وجود كلمات رئيسية وبعض المعرفة الأساسية ، يمكنك تخطي جميع التفاصيل المربكة والخطأ في كثير من الأحيان للنمط غير المتزامن التقليدي. سيكون هذا لا يقدر بثمن في أي تطبيق واجهة المستخدم الرسومية التي تعتمد على الحدث مثل WinForms ، WPF من Silverlight.

الإجابة المقبولة حاليًا مضللة.await لا يتوقف عن أي شيء. بادئ ذي بدء ، يمكن استخدامه فقط في الأساليب أو lambdas. async والعودة Task أو void إذا كنت لا تهتم بوجود Task مثيل تشغيل في هذه الطريقة.

هنا توضيح:

internal class Program
{
    private static void Main(string[] args)
    {
        var task = DoWork();
        Console.WriteLine("Task status: " + task.Status);
        Console.WriteLine("Waiting for ENTER");
        Console.ReadLine();
    }

    private static async Task DoWork()
    {
        Console.WriteLine("Entered DoWork(). Sleeping 3");
        // imitating time consuming code
        // in a real-world app this should be inside task, 
        // so method returns fast
        Thread.Sleep(3000);

        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("async task iteration " + i);
                    // imitating time consuming code
                    Thread.Sleep(1000);
                }
            });

        Console.WriteLine("Exiting DoWork()");
    }
}

انتاج:

دخلت Dowork (). النوم 3
تكرار المهام Async 0
حالة المهمة: Waitingforactivation
في انتظار الدخول
تكرار المهام Async 1
تكرار المهام Async 2
تكرار المهام Async 3
تكرار المهام Async 4
تكرار المهام Async 5
تكرار المهام Async 6
تكرار المهام غير المتزامن 7
تكرار المهام Async 8
تكرار المهام Async 9
الخروج من Dowork ()

لأي شخص جديد في البرمجة غير المتزامنة في .NET، إليك تشبيه (زائف تمامًا) في سيناريو قد تكون أكثر دراية به - مكالمات AJAX باستخدام JavaScript/jQuery.يبدو منشور jQuery AJAX البسيط كما يلي:

$.post(url, values, function(data) {
  // AJAX call completed, do something with returned data here
});

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

الآن، إذا كانت JavaScript تدعم ملف await الكلمة الرئيسية (والتي بالطبع لا (حتى الآن!)))، يمكنك تحقيق نفس الشيء من خلال هذا:

var data = await $.post(url, values);
// AJAX call completed, do something with returned data here

هذا أكثر نظافة، ولكن يبدو بالتأكيد أننا قدمنا ​​كود حظر متزامن.لكن مترجم جافا سكريبت (المزيف) كان سيأخذ كل شيء بعد ذلك await وقمت بتوصيله إلى رد اتصال، لذلك في وقت التشغيل سيتصرف المثال الثاني تمامًا مثل الأول.

قد لا يبدو أنه يوفر عليك الكثير من العمل، ولكن عندما يتعلق الأمر بأشياء مثل معالجة الاستثناءات وسياقات المزامنة، فإن المترجم يقوم في الواقع بما يلي: كثير من الرفع الثقيل بالنسبة لك.للمزيد، أنصحك بـ الأسئلة الشائعة تليها سلسلة بلوق ستيفن كليري.

إذا اضطررت إلى تنفيذها في جافا ، فسيبدو شيء مثل هذا:

/**
 * @author Ilya Gazman
 */
public abstract class SynchronizedTask{

    private ArrayList<Runnable> listeners = new ArrayList<Runnable>();

    private static final ThreadPoolExecutor threadPoolExecutor =  new ThreadPoolExecutor(6, 6, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1000));

    public final void await(Runnable listener){
        synchronized (this) {
            listeners.add(listener);
        }
    }

    public void excecute(){
        onExcecute();
        for (int i = listeners.size() - 1; i >= 0; i--) {
            Runnable runnable;
            synchronized (this) {
                runnable = listeners.remove(i);
            }
            threadPoolExecutor.execute(runnable);
        }
    }

    protected abstract void onExcecute();
}

سوف يستخدمه تطبيقك مثل هذا:

public class Test{
    private Job job = new Job();

    public Test() {
        craeteSomeJobToRunInBackground();
        methode1();
        methode2();
    }

    private void methode1(){
        System.out.println("Running methode 1");
        job.await(new Runnable() {

            @Override
            public void run() {
                System.out.println("Continue to running methode 1");
            }
        });
    }

    private void methode2(){
        System.out.println("Running methode 2");
    }

    private void craeteSomeJobToRunInBackground() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                job.excecute();
            }
        }).start();
    }

    private class Job extends SynchronizedTask{

        @Override
        protected void onExcecute() {
            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Job is done");
        }
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top