في المكتبة الموازية للمهمة: كيفية تأجيل Task.TaskFactory.fromasync تنفيذ المهمة؟

StackOverflow https://stackoverflow.com/questions/4031378

  •  26-09-2019
  •  | 
  •  

سؤال

لدي طريقة تُرجع مهمة مثل:

public static Task<int> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
    if (socket == null) throw new ArgumentNullException("socket");
    if (buffer == null) throw new ArgumentNullException("buffer");

    return Task.Factory.FromAsync<int>(
        socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
        socket.EndSend);
}

أرغب في الحفاظ على الإشارة إلى المهمة وتشغيلها لاحقًا. ومع ذلك ، يبدو أن المهمة التي أنشأتها طريقة FromAsync يتم تنفيذها على الفور. كيف يمكنني تأجيل تنفيذها؟

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

المحلول

بالنسبة للمبتدئين ، إذا نظرت إلى بناء الجملة ، فستدرك أنك تستحضر بالفعل BeginSend طريقة نفسك وتسبب في إعادة IAsyncResult للمعلمة الأولى من FromAsync. هذا مجرد واحد من الحمولة الزائدة من FromAsync رغم ذلك. إذا نظرت إلى وجود أحمال زائدة أخرى وتلك التي تبحث عنها هي تلك التي تأخذ Func<...> في حين أن. لسوء الحظ ، سوف تستدعي هذه الحمولة الزائدة أيضًا الطريقة على الفور نيابة عنك بسبب حقيقة أنه ، تحت الأغطية ، ما يحدث بالفعل هو أن FromAsync هو مجرد لف نمط استدعاء APM باستخدام أ TaskCompletionSource<TResult>.

الطريقة الوحيدة التي يمكنني من خلالها أن أراك في الواقع قادرة على تأجيل التنفيذ هي لف في الواقع FromAsync العمل في مهمة الوالدين التي لا تفعلها Start نفسك. علي سبيل المثال:

public static Task<int> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
    if (socket == null) throw new ArgumentNullException("socket");
    if (buffer == null) throw new ArgumentNullException("buffer");

    return new Task<int>(() =>
    {
        return Task.Factory.FromAsync<int>(
                         socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
                         socket.EndSend).Result;
    }
}

الآن يمكن للمتصل الحصول على المهمة مثل:

Task<int> task = SendAsync(...);

وحتى يتصلون task.Start() لن يبدأ العمل.

نصائح أخرى

إذا كانت الواجهات الخاصة بك تتطلب أن تقوم بإرجاع مهمة ، فقد ينتهي بك الأمر إلى جدولة غير ضرورية على مجموعة مؤشرات الترابط لمجرد إجراء مكالمة BEGINSEND () ).

بدلاً من ذلك ، إذا كنت قادرًا على تغيير الواجهة ، فيمكنك استخدام تقنية تنفيذ تأخير قياسية مثل:

public static Func<Task<int>> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
    if (socket == null) throw new ArgumentNullException("socket");
    if (buffer == null) throw new ArgumentNullException("buffer");
    return () => 
        Task.Factory.FromAsync<int>(
            socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
            socket.EndSend);
}

سوف يستدعي المتصل النتيجة لبدء العملية (أي استدعاء من async/beginsend) واستخدام Continuewith () لمعالجة النتيجة:

Func<Task<int>> sendAsync = socket.SendAsync(buffer, offset, count);
sendAsync().ContinueWith(
    antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));

إذا لم يكن تعريض func <> في واجهتك غير مناسب ، فيمكنك لفه في فئة منفصلة:

public class DelayedTask<TResult>
{
    private readonly Func<Task<TResult>> func;

    public DelayedTask(Func<Task<TResult>> func)
    {
        this.func = func;
    }

    public Task<TResult> Start()
    {
        return this.func();
    }
}

public static DelayedTask<int> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
    if (socket == null) throw new ArgumentNullException("socket");
    if (buffer == null) throw new ArgumentNullException("buffer");
    return new DelayedTask<int>(() =>
        Task.Factory.FromAsync<int>(
            socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
            socket.EndSend));
}

وسيبدو المتصل:

DelayedTask<int> task = socket.SendAsync(buffer, offset, count);
task.Start().ContinueWith(
    antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));

يمكن لفصل المهمة بمهمة أخرى تأجيل التنفيذ.

  // Wrap the task
  var myTask = new Task<Task<int>>(() => SendAsync(...));

  // Defered start
  Thread.Sleep(1000); 
  myTask.Start();
  // Thread is not blocked
  Console.WriteLine("Started");

  // Wait for the result
  Console.WriteLine(myTask.Unwrap().Result);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top