আরম্ভ না করা টাস্ককে কীভাবে ঘোষণা করবেন যা অন্য কোনও টাস্কের জন্য অপেক্ষা করবে?


9

আমি এই ইউনিট পরীক্ষাটি করেছি এবং আমি বুঝতে পারি না যে "টাস্কের জন্য অপেক্ষা করুন। ডেলা ()" কেন অপেক্ষা করে না!

   [TestMethod]
    public async Task SimpleTest()
    {
        bool isOK = false;
        Task myTask = new Task(async () =>
        {
            Console.WriteLine("Task.BeforeDelay");
            await Task.Delay(1000);
            Console.WriteLine("Task.AfterDelay");
            isOK = true;
            Console.WriteLine("Task.Ended");
        });
        Console.WriteLine("Main.BeforeStart");
        myTask.Start();
        Console.WriteLine("Main.AfterStart");
        await myTask;
        Console.WriteLine("Main.AfterAwait");
        Assert.IsTrue(isOK, "OK");
    }

এখানে ইউনিট টেস্ট আউটপুট:

ইউনিট টেস্ট আউটপুট

কীভাবে এটি "অপেক্ষা" করা সম্ভব নয় এবং মূল থ্রেডটি কীভাবে অবিরত থাকবে?


আপনি কী অর্জন করতে চাইছেন তা সামান্য অস্পষ্ট। আপনি দয়া করে আপনার প্রত্যাশিত আউটপুট যোগ করতে পারেন?
ওলেজিআই

1
পরীক্ষার পদ্ধতিটি অত্যন্ত স্পষ্ট - আইসওকে সত্য হতে পারে বলে আশা করা হচ্ছে
স্যার

একটি অ-শুরু করা কার্য তৈরি করার কোনও কারণ নেই। কার্যগুলি থ্রেড নয়, তারা থ্রেড ব্যবহার করে । আপনি কি করতে চেষ্টা করছেন? Task.Run()প্রথমটির পরে কেন ব্যবহার করবেন না Console.WriteLine?
পানাজিওটিস কানভোস

1
@ আপনি কেবল থ্রেডপুলগুলি বর্ণনা করেছেন। আপনি না একটা চাকরি কিউ বাস্তবায়ন কাজগুলো একটি পুল প্রয়োজন। আপনার কাজের একটি সারি প্রয়োজন, উদাহরণস্বরূপ অ্যাকশন <T> বস্তু
পানাজিওটিস কানভোস

2
@ আপনি যা করতে চেষ্টা করছেন তা সমস্তই ইতিমধ্যে .NET- এ পাওয়া যায় Action্যাকশনব্লকের মতো টিপিএল ডেটাফ্লো ক্লাসগুলির মাধ্যমে, বা আরও নতুন সিস্টেম h থ্রেডিং C চ্যানেল ক্লাস। আপনি এক বা একাধিক সমবর্তী টাস্ক ব্যবহার করে বার্তাগুলি গ্রহণ এবং প্রক্রিয়া করার জন্য অ্যাকশনব্লক তৈরি করতে পারেন। সমস্ত ব্লকের কনফিগারযোগ্য ক্ষমতা সহ ইনপুট বাফার রয়েছে। ডিওপি এবং ক্ষমতা আপনাকে সামঞ্জস্য নিয়ন্ত্রণ করতে, থ্রটল অনুরোধ করতে এবং ব্যাকপ্রেসার বাস্তবায়নের অনুমতি দেয় - যদি খুব বেশি বার্তাগুলি সারিবদ্ধ থাকে তবে নির্মাতা অপেক্ষা করতে পারেন
পানাগিওটিস কানভোস

উত্তর:


8

new Task(async () =>

একটি কাজ একটি লাগে না Func<Task>, কিন্তু একটি Action। এটি আপনার অ্যাসিক্রোনাস পদ্ধতিতে কল করবে এবং প্রত্যাবর্তনের পরে এটি শেষ হবে expect তবে তা হয় না। এটি একটি কাজ ফিরে। নতুন টাস্কের জন্য সেই টাস্কটি অপেক্ষা করা হয় না। নতুন কাজের জন্য, পদ্ধতিটি ফিরে আসার পরে এই কাজটি করা হয়।

আপনাকে নতুন টাস্কে মোড়কের পরিবর্তে ইতিমধ্যে বিদ্যমান কাজটি ব্যবহার করতে হবে:

[TestMethod]
public async Task SimpleTest()
{
    bool isOK = false;

    Func<Task> asyncMethod = async () =>
    {
        Console.WriteLine("Task.BeforeDelay");
        await Task.Delay(1000);
        Console.WriteLine("Task.AfterDelay");
        isOK = true;
        Console.WriteLine("Task.Ended");
    };

    Console.WriteLine("Main.BeforeStart");
    Task myTask = asyncMethod();

    Console.WriteLine("Main.AfterStart");

    await myTask;
    Console.WriteLine("Main.AfterAwait");
    Assert.IsTrue(isOK, "OK");
}

4
Task.Run(async() => ... )এছাড়াও একটি বিকল্প
স্যার রুফো

আপনি কেবল প্রশ্নের লেখক হিসাবে একই করেছেন
ওলিগি

বিটিডাব্লু myTask.Start();একটি উত্থাপন করবেInvalidOperationException
স্যার রুফো

@ ওলিগি আমি এটি দেখতে পাচ্ছি না। আপনি দয়া করে এটি ব্যাখ্যা করতে পারেন?
nvoigt

@ এনভয়েগ্ট আমি ধরে নিয়েছি যে তার অর্থ myTask.Start()তার বিকল্পের জন্য ব্যতিক্রম ঘটবে এবং ব্যবহারের সময় অপসারণ করা উচিত Task.Run(...)। আপনার সমাধানে কোনও ত্রুটি নেই।
404

3

সমস্যাটি হ'ল আপনি নন-জেনেরিক Taskক্লাসটি ব্যবহার করছেন , এটি কোনও ফলাফল তৈরি করার উদ্দেশ্যে নয়। সুতরাং আপনি যখন Taskঅ্যাসিঙ্ক প্রতিনিধিকে পাশ করার উদাহরণটি তৈরি করবেন :

Task myTask = new Task(async () =>

... প্রতিনিধি হিসাবে বিবেচিত হয় async void। এটি একটি async voidনয় Task, এটির জন্য অপেক্ষা করা যায় না, এর ব্যতিক্রমটি পরিচালনা করা যায় না, এবং এটি স্ট্যাকওভারফ্লো এবং অন্য কোথাও হতাশ প্রোগ্রামারদের দ্বারা তৈরি হাজার হাজার প্রশ্নের উত্স । সমাধানটি হ'ল জেনেরিক Task<TResult>ক্লাসটি ব্যবহার করা , কারণ আপনি একটি ফলাফল ফিরে আসতে চান এবং ফলাফলটি অন্য Task। সুতরাং আপনাকে একটি তৈরি করতে হবে Task<Task>:

Task<Task> myTask = new Task<Task>(async () =>

এখন যখন আপনি Startবাইরের দিকে যান তখন Task<Task>এটি প্রায় তাত্ক্ষণিকভাবে সম্পন্ন হবে কারণ এর কাজটি কেবল অন্তর্ তৈরি করা Task। এরপরে আপনাকে অভ্যন্তরেরও অপেক্ষা করতে হবে Task। এটি এটি করা যেতে পারে:

myTask.Start();
Task myInnerTask = await myTask;
await myInnerTask;

আপনার দুটি বিকল্প আছে। আপনার যদি অভ্যন্তরীণ বিষয়ে সুস্পষ্ট রেফারেন্সের প্রয়োজন না হয় Taskতবে আপনি কেবল Task<Task>দু'বার বাইরের জন্য অপেক্ষা করতে পারেন :

await await myTask;

... বা আপনি অন্তর্নির্মিত এক্সটেনশন পদ্ধতিটি ব্যবহার করতে পারেন Unwrapযা বাইরের এবং অভ্যন্তরীণ কার্যগুলিকে একের সাথে সংযুক্ত করে:

await myTask.Unwrap();

আপনি যখন আরও বেশি জনপ্রিয় ব্যবহার করেন তখন এই আনারপিংটি স্বয়ংক্রিয়ভাবে ঘটে Task.Run গরম কাজগুলি তৈরি করে এমন পদ্ধতি so তাই Unwrapআজকাল খুব সহজেই এটি ব্যবহৃত হয় না।

আপনি যদি সিদ্ধান্ত নেন যে আপনার অ্যাসিঙ্ক প্রতিনিধিকে অবশ্যই একটি ফলাফল ফেরত পাঠাতে হবে, উদাহরণস্বরূপ ক string, তারপরে আপনার ফলাফলটি ঘোষণা করা উচিতmyTask পাঠাতে হবে ভেরিয়েবলটি টাইপ হিসাবেTask<Task<string>>

দ্রষ্টব্য: আমি এর ব্যবহারকে সমর্থন করি নাTask ঠান্ডা কাজ তৈরির জন্য কনস্ট্রাক্টর । যেহেতু একটি অনুশীলনটি সাধারণত নষ্ট হয়, কারণগুলির কারণে আমি সত্যিই জানি না, তবে সম্ভবত এটি এত কম ব্যবহৃত হয় যে এতে অন্য অজ্ঞাত ব্যবহারকারী / রক্ষণাবেক্ষণকারী / কোডটির পর্যালোচকদের অবাক করে তোলার সম্ভাবনা রয়েছে।

সাধারণ পরামর্শ: আপনি যখন কোনও পদ্ধতির তর্ক হিসাবে একটি অ্যাসিঙ্ক প্রতিনিধি সরবরাহ করছেন তখন প্রতিবার সতর্ক থাকুন। এই পদ্ধতির আদর্শভাবে একটি Func<Task>যুক্তি (অর্থাত্ async প্রতিনিধিদের বোঝে) বা কমপক্ষে একটি Func<T>যুক্তি (যার অর্থ কমপক্ষে উত্পন্ন উত্পন্ন করা Taskহবে তা উপেক্ষা করা হবে না) আশা করা উচিত। দুর্ভাগ্যজনক ক্ষেত্রে যে এই পদ্ধতিটি একটি গ্রহণ করে Action, আপনার প্রতিনিধি হিসাবে বিবেচিত হবে async void। এটি যদি আপনি চান তবে খুব কমই হয়।


কীভাবে বিস্তারিত প্রযুক্তিগত উত্তর! ধন্যবাদ.
এলো

@ সব আমার আনন্দ!
থিওডর জোলিয়াস

1
 [Fact]
        public async Task SimpleTest()
        {
            bool isOK = false;
            Task myTask = new Task(() =>
            {
                Console.WriteLine("Task.BeforeDelay");
                Task.Delay(3000).Wait();
                Console.WriteLine("Task.AfterDelay");
                isOK = true;
                Console.WriteLine("Task.Ended");
            });
            Console.WriteLine("Main.BeforeStart");
            myTask.Start();
            Console.WriteLine("Main.AfterStart");
            await myTask;
            Console.WriteLine("Main.AfterAwait");
            Assert.True(isOK, "OK");
        }

এখানে চিত্র বর্ণনা লিখুন


3
আপনি বুঝতে পেরেছেন যে await, কার্যবিবরণীতে দেরি আসলে কার্যত বিলম্ব করবে না, তাই না? আপনি কার্যকারিতা সরিয়েছেন।
19 '

আমি কেবল পরীক্ষা করেছি, @ এনভিগইট সঠিক: অতিবাহিত সময়: 0: 00: 00,0106554। এবং আমরা আপনার স্ক্রিনশটে দেখতে পাচ্ছি: "অতিবাহিত সময়: 18 এমএস", এটি হওয়া উচিত = = 1000 এমএস
এলো

হ্যাঁ আপনি ঠিক বলেছেন, আমি আমার প্রতিক্রিয়া আপডেট করি। Tnx। আপনি মন্তব্য করার পরে আমি এটি ন্যূনতম পরিবর্তনগুলির সাথে সমাধান করব। :)
বাসকা

1
অপেক্ষা () ব্যবহার করা এবং কোনও কার্যের ভিতরে থেকে অপেক্ষা না করার জন্য ভাল ধারণা! ধন্যবাদ!
এলো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.