টাস্ক কনস্ট্রাক্টরে বাতিল টোকেন: কেন?


223

কিছু নির্মাতা প্যারামিটার হিসাবে System.Threading.Tasks.Taskগ্রহণ করে CancellationToken:

CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);

কি আমাকে এই বিষয়ে ধাঁধাঁর মতো থেকে কোন উপায় নেই যে আছে ভিতরে পদ্ধতি শরীর আসলে টোকেন (যেমন, মত কিছুই পাস এ পেতে Task.CurrentTask.CancellationToken)। টোকেনটি অন্য কিছু পদ্ধতির মাধ্যমে সরবরাহ করতে হবে, যেমন রাষ্ট্রীয় বস্তু বা ল্যাম্বডায় বন্দী।

সুতরাং কনস্ট্রাক্টর বাতিল টোকেন সরবরাহ করে কি উদ্দেশ্যে?

উত্তর:


254

কন্সট্রাক্টরের একটি পাস CancellationTokenকরা Taskএটিকে কাজের সাথে যুক্ত করে।

এমএসডিএন থেকে স্টিফেন টুবের উত্তর উদ্ধৃত :

এর দুটি প্রাথমিক সুবিধা রয়েছে:

  1. যদি টোকেনটি Taskকার্যকর করার শুরুর আগে বাতিলকরণের অনুরোধ করে থাকে তবে কার্যকর Taskহবে না। পরিবর্তিত হওয়ার পরিবর্তে Running, এটি অবিলম্বে স্থানান্তরিত হবে Canceled। এটি যদি কোনওভাবেই চালানোর সময় কেবল বাতিল হয়ে যায় তবে কাজটি চালনার ব্যয় এড়ানো হবে।
  2. যদি টাস্কের বডিটি বাতিলকরণ টোকেনটিও পর্যবেক্ষণ করে এবং সেই টোকেনযুক্ত একটি OperationCanceledException(যা তা ThrowIfCancellationRequestedকরে) ফেলে দেয়, তবে যখন টাস্কটি এটি দেখে OperationCanceledException, এটি পরীক্ষা OperationCanceledExceptionকরে টাস্কের টোকনটির সাথে মেলে কিনা । যদি এটি হয়, তবে এই ব্যতিক্রমটিকে সমবায় বাতিলকরণের স্বীকৃতি এবং রাজ্যে Taskস্থানান্তরিতকরণ Canceled(রাষ্ট্রের পরিবর্তে Faulted) হিসাবে দেখা হয়।

2
টিপিএল এত ভাল চিন্তা করা হয়।
কর্নেল আতঙ্ক

1
আমি ধরে নিলাম বেনিফিট 1 একটি বাতিলকরণ টোকন পাস করার অনুরূপ Parallel.Forবা একইভাবে প্রযোজ্যParallel.ForEach
কর্নেল প্যানিক

27

কনস্ট্রাক্টর অভ্যন্তরীণভাবে বাতিল হ্যান্ডলিংয়ের জন্য টোকেন ব্যবহার করে। যদি আপনার কোড টোকেনে অ্যাক্সেস করতে চান তবে আপনি এটি নিজের কাছে দেওয়ার জন্য দায়বদ্ধ। আমি কোডপ্লেক্সে মাইক্রোসফ্ট .NET বইয়ের সাথে সমান্তরাল প্রোগ্রামিং পড়ার সুপারিশ করব ।

বইটি থেকে সিটিএস ব্যবহারের উদাহরণ:

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task myTask = Task.Factory.StartNew(() =>
{
    for (...)
    {
        token.ThrowIfCancellationRequested();

        // Body of for loop.
    }
}, token);

// ... elsewhere ...
cts.Cancel();

3
এবং যদি আপনি পরামিতি হিসাবে টোকেন পাস না করেন তবে কি হবে? দেখে মনে হচ্ছে আচরণ একই হবে, উদ্দেশ্য নেই।
সার্জটেক

2
@ সের্গদেব: আপনি টাস্কটি এটিকে টাস্ক এবং সময়সূচী দিয়ে রেজিস্ট্রেশন করতে পাস করেছেন। এটি পাস না করা এবং এটি ব্যবহার করা হবে সংজ্ঞায়িত আচরণ।
ব্যবহারকারী 7116

3
@ সের্গদেব: পরীক্ষার পরে: আপনি যখন প্যারামিটার হিসাবে টোকেনটি পাস না করেন তখন myTask.IsCanceled এবং myTask.Status এক নয়। স্থিতি বাতিল হওয়ার পরিবর্তে ব্যর্থ হবে। তবে ব্যতিক্রম একই: এটি উভয় ক্ষেত্রেই একটি অপারেশন-ক্যান্সেলড এক্সসেপশন।
অলিভিয়ের ডি রিভয়ের

2
আমি যদি ফোন না করি token.ThrowIfCancellationRequested();? আমার পরীক্ষায়, আচরণ একই রকম। কোন ধারনা?
ম্যাকিনারিয়াম

1
@ কোবাল্ট ব্লু: when cts.Cancel() is called the Task is going to get canceled and end, no matter what you doনা যদি কাজটি শুরু হওয়ার আগেই বাতিল হয়ে যায় তবে তা বাতিল হয়ে যায় । যদি টাস্কের বডিটি সহজেই কোনও টোকেন চেক করে না, তবে এটি সম্পূর্ণরূপে চলে যাবে, যার ফলে রানটোকম্প্লেশন স্থিতি হবে। যদি শরীরে কোনও একটি ফেলে দেয় OperationCancelledException, উদাহরণস্বরূপ ThrowIfCancellationRequested, তবে টাস্ক পরীক্ষা করবে যে ব্যতিক্রমটির বাতিলকরণ টোকন টাস্কের সাথে সম্পর্কিত একটির মতো কিনা। যদি তা হয় তবে কাজটি বাতিল হয়ে যায় । যদি তা না হয় তবে এটি ত্রুটিযুক্ত
ওল্ফজুন

7

বাতিল মনে করা সহজ বিষয় নয় যা অনেকে ভাবেন। এমএসডিএন-তে এই ব্লগ পোস্টে কিছু সূক্ষ্মতা ব্যাখ্যা করা হয়েছে:

উদাহরণ স্বরূপ:

সমান্তরাল এক্সটেনশানগুলির এবং অন্যান্য সিস্টেমে নির্দিষ্ট পরিস্থিতিতে কোনও ব্যবহারকারীর দ্বারা সুস্পষ্ট বাতিলকরণের কারণে নয় এমন কারণে একটি অবরুদ্ধ পদ্ধতি জাগানো প্রয়োজন। উদাহরণস্বরূপ, যদি blockingCollection.Take()সংগ্রহটি খালি থাকার কারণে যদি একটি থ্রেড অবরুদ্ধ থাকে এবং পরে অন্য থ্রেড কল করে blockingCollection.CompleteAdding(), তবে প্রথম কলটি জেগে উঠতে হবে এবং InvalidOperationExceptionএকটি ভুল ব্যবহার উপস্থাপন করার জন্য একটি নিক্ষেপ করা উচিত ।

সমান্তরাল এক্সটেনশনে বাতিল lation


4

এখানে একটি উদাহরণ যে দুই পয়েন্ট প্রমান হয় উত্তর দ্বারা ম্যাক্স Galkin :

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("*********************************************************************");
        Console.WriteLine("* Start canceled task, don't pass token to constructor");
        Console.WriteLine("*********************************************************************");
        StartCanceledTaskTest(false);
        Console.WriteLine();

        Console.WriteLine("*********************************************************************");
        Console.WriteLine("* Start canceled task, pass token to constructor");
        Console.WriteLine("*********************************************************************");
        StartCanceledTaskTest(true);
        Console.WriteLine();

        Console.WriteLine("*********************************************************************");
        Console.WriteLine("* Throw if cancellation requested, don't pass token to constructor");
        Console.WriteLine("*********************************************************************");
        ThrowIfCancellationRequestedTest(false);
        Console.WriteLine();

        Console.WriteLine("*********************************************************************");
        Console.WriteLine("* Throw if cancellation requested, pass token to constructor");
        Console.WriteLine("*********************************************************************");
        ThrowIfCancellationRequestedTest(true);
        Console.WriteLine();

        Console.WriteLine();
        Console.WriteLine("Test Done!!!");
        Console.ReadKey();
    }

    static void StartCanceledTaskTest(bool passTokenToConstructor)
    {
        Console.WriteLine("Creating task");
        CancellationTokenSource tokenSource = new CancellationTokenSource();
        Task task = null;
        if (passTokenToConstructor)
        {
            task = new Task(() => TaskWork(tokenSource.Token, false), tokenSource.Token);

        }
        else
        {
            task = new Task(() => TaskWork(tokenSource.Token, false));
        }

        Console.WriteLine("Canceling task");
        tokenSource.Cancel();

        try
        {
            Console.WriteLine("Starting task");
            task.Start();
            task.Wait();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: {0}", ex.Message);
            if (ex.InnerException != null)
            {
                Console.WriteLine("InnerException: {0}", ex.InnerException.Message);
            }
        }

        Console.WriteLine("Task.Status: {0}", task.Status);
    }

    static void ThrowIfCancellationRequestedTest(bool passTokenToConstructor)
    {
        Console.WriteLine("Creating task");
        CancellationTokenSource tokenSource = new CancellationTokenSource();
        Task task = null;
        if (passTokenToConstructor)
        {
            task = new Task(() => TaskWork(tokenSource.Token, true), tokenSource.Token);

        }
        else
        {
            task = new Task(() => TaskWork(tokenSource.Token, true));
        }

        try
        {
            Console.WriteLine("Starting task");
            task.Start();
            Thread.Sleep(100);

            Console.WriteLine("Canceling task");
            tokenSource.Cancel();
            task.Wait();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: {0}", ex.Message);
            if (ex.InnerException != null)
            {
                Console.WriteLine("InnerException: {0}", ex.InnerException.Message);
            }
        }

        Console.WriteLine("Task.Status: {0}", task.Status);
    }

    static void TaskWork(CancellationToken token, bool throwException)
    {
        int loopCount = 0;

        while (true)
        {
            loopCount++;
            Console.WriteLine("Task: loop count {0}", loopCount);

            token.WaitHandle.WaitOne(50);
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Task: cancellation requested");
                if (throwException)
                {
                    token.ThrowIfCancellationRequested();
                }

                break;
            }
        }
    }
}

আউটপুট:

*********************************************************************
* Start canceled task, don't pass token to constructor
*********************************************************************
Creating task
Canceling task
Starting task
Task: loop count 1
Task: cancellation requested
Task.Status: RanToCompletion

*********************************************************************
* Start canceled task, pass token to constructor
*********************************************************************
Creating task
Canceling task
Starting task
Exception: Start may not be called on a task that has completed.
Task.Status: Canceled

*********************************************************************
* Throw if cancellation requested, don't pass token to constructor
*********************************************************************
Creating task
Starting task
Task: loop count 1
Task: loop count 2
Canceling task
Task: cancellation requested
Exception: One or more errors occurred.
InnerException: The operation was canceled.
Task.Status: Faulted

*********************************************************************
* Throw if cancellation requested, pass token to constructor
*********************************************************************
Creating task
Starting task
Task: loop count 1
Task: loop count 2
Canceling task
Task: cancellation requested
Exception: One or more errors occurred.
InnerException: A task was canceled.
Task.Status: Canceled


Test Done!!!
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.