টাস্ক.রুন () এবং টাস্ক.ফ্যাক্টরি.স্টার্টনিউ () এর মধ্যে পার্থক্য কী


190

আমার পদ্ধতি আছে:

private static void Method()
{
    Console.WriteLine("Method() started");

    for (var i = 0; i < 20; i++)
    {
        Console.WriteLine("Method() Counter = " + i);
        Thread.Sleep(500);
    }

    Console.WriteLine("Method() finished");
}

এবং আমি এই পদ্ধতিটি একটি নতুন টাস্কে শুরু করতে চাই। আমি এভাবে নতুন কাজ শুরু করতে পারি

var task = Task.Factory.StartNew(new Action(Method));

অথবা এটা

var task = Task.Run(new Action(Method));

তবে Task.Run()এবং এর মধ্যে কোনও পার্থক্য আছে কি Task.Factory.StartNew()? তারা উভয়ই থ্রেডপুল ব্যবহার করছে এবং কার্যটির উদাহরণ তৈরি করার সাথে সাথেই পদ্ধতি () শুরু করে। আমাদের প্রথম রূপটি কখন ব্যবহার করা উচিত এবং কখন দ্বিতীয়?


6
আসলে, স্টার্টনিউকে থ্রেডপুল ব্যবহার করতে হবে না, আমার উত্তরে আমি যে ব্লগটি লিঙ্ক করেছি তা দেখুন। সমস্যাটি StartNewডিফল্ট ব্যবহারের দ্বারা হয় TaskScheduler.Currentযা থ্রেড পুল হতে পারে তবে ইউআই থ্রেডও হতে পারে।
স্কট চেম্বারলাইন

উত্তর:


195

দ্বিতীয় পদ্ধতিটি, Task.Run.NET ফ্রেমওয়ার্কের (সংস্করণ .NET 4.5) পরবর্তী সংস্করণে চালু করা হয়েছে।

যাইহোক, প্রথম পদ্ধতিটি, Task.Factory.StartNewআপনাকে যে থ্রেডটি তৈরি করতে চান তার সম্পর্কে প্রচুর দরকারী জিনিস সংজ্ঞা দেওয়ার সুযোগ দেয়, যখন এটি সরবরাহ Task.Runকরে না।

উদাহরণস্বরূপ, ধরুন যে আপনি একটি দীর্ঘ চলমান টাস্ক থ্রেড তৈরি করতে চান। এই কাজের জন্য যদি থ্রেড পুলের কোনও থ্রেড ব্যবহার করা হয়, তবে এটি থ্রেড পুলের অপব্যবহার হিসাবে বিবেচিত হতে পারে।

এটি এড়াতে আপনি যা করতে পারেন তা হ'ল কাজটি আলাদা থ্রেডে চালানো। একটি নতুন তৈরি থ্রেড যা এই কাজের জন্য নিবেদিত হবে এবং আপনার কাজটি শেষ হয়ে গেলে তা ধ্বংস হয়ে যাবে। আপনি করতে পারবেন না সঙ্গে এই অর্জন Task.Run, যখন আপনার সাথে তা করতে পারেন Task.Factory.StartNewনিচের মত:

Task.Factory.StartNew(..., TaskCreationOptions.LongRunning);

যেমনটি এখানে বলা হয়েছে :

সুতরাং, .NET ফ্রেমওয়ার্ক 4.5 বিকাশকারী পূর্বরূপে, আমরা নতুন Task.Run পদ্ধতিটি চালু করেছি। এটি কোনওভাবেই টাস্ক.ফ্যাক্টরি.স্টার্টনউকে অচল করে না, বরং কেবলমাত্র প্যারামিতিগুলির একগুচ্ছ নির্দিষ্টকরণের প্রয়োজন ছাড়াই টাস্ক.ফ্যাক্ট্রি.স্টার্টনিউ ব্যবহার করার দ্রুত উপায় হিসাবে ভাবা উচিত এটি একটি শর্টকাট। প্রকৃতপক্ষে, Task.Run আসলে টাস্ক.ফ্যাক্টরি.স্টার্টনিউয়ের জন্য ব্যবহৃত একই যুক্তির পরিপ্রেক্ষিতে বাস্তবায়িত হয়, কিছু ডিফল্ট প্যারামিটারে কেবল উত্তীর্ণ হয়। আপনি যখন কোনও অ্যাকশন টাস্কে পাস করেন un

Task.Run(someAction);

এটি ঠিক সমান:

Task.Factory.StartNew(someAction, 
    CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

4
আমার কাছে কোডের একটি টুকরা রয়েছে যেখানে স্টেটম্যান্ট that’s exactly equivalent toরাখে না।
ইমাবোরসা

7
@ এমবার্সা আমি প্রশংসা করব যদি আপনি এই টুকরো কোডটি পোস্ট করতে এবং আপনার যুক্তিটি বিস্তারিতভাবে বর্ণনা করতে পারেন। আগাম ধন্যবাদ !
ক্রিস্টোজ

4
@ এমবার্সা আপনি একটি টুকরোটি , gist.github.com তৈরি করতে এবং এটি ভাগ করে নিতে পারেন। যাইহোক, এই টুকরোটি ভাগ করে নেওয়া ব্যতীত দয়া করে নির্দিষ্ট করুন যে আপনি কীভাবে সেই ফলাফলটি পেয়েছিলেন যা বাক্যাংশটি tha's exactly equivalent toধারণ করে না। আগাম ধন্যবাদ. আপনার কোডটিতে মন্তব্য সহ ব্যাখ্যা দিয়ে ভাল লাগবে। ধন্যবাদ :)
ক্রিস্টোস

8
এটিও উল্লেখযোগ্য যে Task.Run ডিফল্টরূপে নেস্টেড টাস্কটি আন-র্যাপ করুন। আমি এই নিবন্ধটি বড় পার্থক্যগুলি সম্পর্কে পড়ার পরামর্শ দিচ্ছি: ব্লগস.এমএসএনএন.মাইক্রোসফট.কম
পাভেল মাগা

1
@ থ0bserver নাহ, এটি TaskScheduler.Defaultরেফারেন্সসোর্স.মাইক্রোসফট . com/#mscorlib/system/threading/Tasks/ … এখানে একবার দেখুন ।
ক্রিস্টোজ

46

লোকেরা ইতিমধ্যে এটি উল্লেখ করেছে

Task.Run(A);

এর সমতুল্য

Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

তবে কেউ তা উল্লেখ করেনি

Task.Factory.StartNew(A);

এর সমতুল্য:

Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

আপনি দেখতে পাচ্ছেন দুটি পরামিতি আলাদা Task.Runএবং এর জন্যTask.Factory.StartNew :

  1. TaskCreationOptions- Task.Runব্যবহারTaskCreationOptions.DenyChildAttach যার অর্থ হল যে বাচ্চাদের কার্যগুলি পিতামাতার সাথে সংযুক্ত করা যায় না, এটি বিবেচনা করুন:

    var parentTask = Task.Run(() =>
    {
        var childTask = new Task(() =>
        {
            Thread.Sleep(10000);
            Console.WriteLine("Child task finished.");
        }, TaskCreationOptions.AttachedToParent);
        childTask.Start();
    
        Console.WriteLine("Parent task finished.");
    });
    
    parentTask.Wait();
    Console.WriteLine("Main thread finished.");

    আমরা যখন ডাকা parentTask.Wait(), childTaskপ্রতীক্ষিত হবে না, যদিও আমরা নিদিষ্ট TaskCreationOptions.AttachedToParentজন্য, এই কারণ TaskCreationOptions.DenyChildAttachনিষেধের শিশু এটি সংযুক্ত করতে। আপনার সাথে একই কোড রান তাহলে Task.Factory.StartNewপরিবর্তে Task.Run, parentTask.Wait()জন্য অপেক্ষা করব childTaskকারণ Task.Factory.StartNewব্যবহারসমূহTaskCreationOptions.None

  2. TaskScheduler- Task.Runব্যবহার করে TaskScheduler.Defaultযার অর্থ হ'ল ডিফল্ট টাস্ক শিডিয়ুলার (থ্রেড পুলের উপর একটি কাজ চালায়) সর্বদা কার্য চালনার জন্য ব্যবহৃত হবে। Task.Factory.StartNewঅন্যদিকে ব্যবহার করে TaskScheduler.Currentযার অর্থ বর্তমান থ্রেডের শিডিয়ুলার, এটি হতে পারে TaskScheduler.Defaultতবে সর্বদা না। প্রকৃতপক্ষে বিকাশকারী Winformsবা WPFঅ্যাপ্লিকেশনগুলির সময় বর্তমান থ্রেড থেকে ইউআই আপডেট করার প্রয়োজন হয়, এই লোকেরা TaskScheduler.FromCurrentSynchronizationContext()টাস্ক শিডিয়ুলার ব্যবহার করার জন্য, আপনি যদি অনিচ্ছাকৃতভাবে টাস্কের ভিতরে আরও একটি দীর্ঘ চলমান টাস্ক তৈরি করেন যা TaskScheduler.FromCurrentSynchronizationContext()শিডিয়ুলার ইউআই ব্যবহার করে তা হিমায়িত হয়ে যায়। এর আরও বিস্তারিত ব্যাখ্যা এখানে পাওয়া যাবে

সুতরাং সাধারণত যদি আপনি নেস্টেড বাচ্চাদের কাজটি ব্যবহার না করে থাকেন এবং সর্বদা আপনার কাজগুলি থ্রেড পুলে সম্পাদন করতে চান Task.Runতবে আপনার আরও জটিল পরিস্থিতি না থাকলে ব্যবহার করা ভাল ।


1
এটি একটি দুর্দান্ত টিপ, গ্রহণযোগ্য উত্তর হওয়া উচিত
আলী বায়াত


28

Task.Runনতুন .NET Framework সংস্করণ চালু নিয়েছিলাম এবং এটি করা হয় সুপারিশ করা

.NET ফ্রেমওয়ার্ক 4.5 দিয়ে শুরু করে, টাস্ক.রুন পদ্ধতিটি একটি গণনা-সীমাবদ্ধ টাস্কটি চালু করার প্রস্তাবিত উপায়। আপনি যখন দীর্ঘকালীন, গণনা-সীমাবদ্ধ কার্যের জন্য সূক্ষ্ম-দানাযুক্ত নিয়ন্ত্রণের প্রয়োজন তখনই স্টার্টনিউ পদ্ধতিটি ব্যবহার করুন।

Task.Factory.StartNewআরও বিকল্প আছে, Task.Runএকটি সাঁটে লেখার হল:

রান পদ্ধতিটি ওভারলোডের একটি সেট সরবরাহ করে যা ডিফল্ট মান ব্যবহার করে কোনও কাজ শুরু করা সহজ করে তোলে। এটি স্টার্টনিউ ওভারলোডগুলির একটি হালকা ওজনের বিকল্প।

এবং শর্টহ্যান্ড বলতে আমার অর্থ প্রযুক্তিগত শর্টকাট :

public static Task Run(Action action)
{
    return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default,
        TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
}

21

স্টিফেন ক্লিয়ারির এই পোস্ট অনুসারে, Task.Factory.StartNew () বিপজ্জনক:

আমি ব্লগ এবং এসও প্রশ্নগুলিতে প্রচুর কোড দেখতে পাচ্ছি যা একটি পটভূমির থ্রেডে কাজ সজ্জিত করার জন্য টাস্ক.ফ্যাক্টরি.স্টার্টনিউ ব্যবহার করে। স্টিফেন টুবের একটি দুর্দান্ত ব্লগ নিবন্ধ রয়েছে যা ব্যাখ্যা করে যে কেন টাস্ক.ফ্যাক্টরি.স্টার্টনউয়ের চেয়ে টাস্ক রুন ভাল better তবে আমি মনে করি যে অনেক লোক কেবল এটি পড়েনি (বা এটি বুঝতে পারে না)। সুতরাং, আমি একই যুক্তি নিয়েছি, আরও কিছু জোরালো ভাষা যুক্ত করেছি এবং আমরা কীভাবে এটি দেখতে পাব। :) স্টার্টনিউ টাস্ক.রুনের চেয়ে আরও অনেকগুলি বিকল্প প্রস্তাব করে, তবে এটি বেশ বিপজ্জনক, যেমনটি আমরা দেখব। আপনার async কোডে Task.Fun.StartNew এর চেয়ে বেশি কাজ করা উচিত।

আসল কারণগুলি এখানে:

  1. অ্যাসিঙ্ক প্রতিনিধিরা বুঝতে পারে না। আপনি যে কারণে স্টার্টনিউ ব্যবহার করতে চান তা এটি পয়েন্ট 1 এর সমান। সমস্যাটি হ'ল আপনি যখন স্টার্টনিউতে একটি অ্যাসিঙ্ক প্রতিনিধি পাস করেন, তখন অনুমান করা স্বাভাবিক যে প্রত্যাবর্তিত টাস্কটি সেই প্রতিনিধিকে উপস্থাপন করে। তবে যেহেতু স্টার্টনিউ অ্যাসিঙ্ক প্রতিনিধিদের বুঝতে পারে না, তাই সেই কাজটি আসলে প্রতিনিধিত্বকারীদের কেবল শুরু। এটি অসিঙ্ক কোডটিতে স্টার্টনিউ ব্যবহার করার সময় কোডারগুলির মধ্যে প্রথম যে কোনও সমস্যার মুখোমুখি হয়।
  2. বিভ্রান্ত ডিফল্ট শিডিয়ুলার। ঠিক আছে, প্রশ্ন সময়: কৌশল নীচের কোডে, "এ" পদ্ধতিটি কোন থ্রেডে চলে?
Task.Factory.StartNew(A);

private static void A() { }

ঠিক আছে, আপনি জানেন যে এটি একটি কৌশল প্রশ্ন, তাই না? আপনি যদি "একটি থ্রেড পুলের থ্রেড" উত্তর দিয়ে থাকেন তবে আমি দুঃখিত, তবে এটি সঠিক নয়। টাস্কশেডুলার বর্তমানে যা চালাচ্ছে তার উপর "এ" চলবে!

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

আমার ক্ষেত্রে, আমি ব্যস্ত অ্যানিমেশনটি প্রদর্শন করার জন্য একটি দিতাগুলি লোড করার সময় পটভূমিতে কাজগুলি চালানোর চেষ্টা করছিলাম। ব্যস্ত অ্যানিমেশনটি ব্যবহার Task.Factory.StartNew()করার সময় প্রদর্শিত হয়নি তবে আমি স্যুইচ করলে অ্যানিমেশনটি সঠিকভাবে প্রদর্শিত হয় Task.Run()

বিশদগুলির জন্য, দয়া করে দেখুন https://blog.stephencleary.com/2013/08/startnew-is-danजर.html


1

টাস্ক.ফ্যাক্টরি.স্টার্টনিউ () -এর জন্য শর্টহ্যান্ড হ'ল টাস্ক.রুন () মিলগুলি ছাড়াও, সিঙ্ক এবং অ্যাসিঙ্ক প্রতিনিধিদের ক্ষেত্রে তাদের আচরণের মধ্যে এক মিনিটের পার্থক্য রয়েছে।

ধরুন এখানে দুটি পদ্ধতি রয়েছে:

public async Task<int> GetIntAsync()
{
    return Task.FromResult(1);
}

public int GetInt()
{
    return 1;
}

এখন নিম্নলিখিত কোড বিবেচনা করুন।

var sync1 = Task.Run(() => GetInt());
var sync2 = Task.Factory.StartNew(() => GetInt());

এখানে সিঙ্ক 1 এবং সিঙ্ক 2 উভয়ই টাস্ক <int> টাইপের

তবে, অ্যাসিঙ্ক পদ্ধতির ক্ষেত্রে পার্থক্য আসে।

var async1 = Task.Run(() => GetIntAsync());
var async2 = Task.Factory.StartNew(() => GetIntAsync());

এই দৃশ্যে, async1 টাইপ টাস্ক <টাইপ>, তবে async2 টাইপ টাস্ক <টাস্ক <int>> টাইপের


হ্যাঁ, কারণ পদ্ধতিটির Task.Runমোড়কানো কার্যকারিতা বিল্ট-ইন রয়েছে Unwrap। এই সিদ্ধান্তের পিছনে যুক্তি ব্যাখ্যা করার জন্য এখানে একটি ব্লগ পোস্ট রয়েছে।
থিওডর জোলিয়াস

-8

আমার অ্যাপ্লিকেশনটিতে যা দুটি পরিষেবা কল করে, আমি টাস্ক.রুন এবং টাস্ক.ফ্যাক্টরি.স্টার্টনউ উভয়ের সাথে তুলনা করেছি । আমি দেখেছি যে আমার ক্ষেত্রে উভয়ই ঠিকঠাক কাজ করে। তবে দ্বিতীয়টি দ্রুততর।


আমি জানি না কেন এই উত্তরটি "10" ডাউন-ভোটের দাবিদার, যদিও এটি সঠিক বা সহায়ক নাও হতে পারে ...
মেয়ার স্পিৎজার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.