TaskCompletionSource <T> কখন ব্যবহার করা উচিত?


199

আফাইক, এটি সমস্ত জানেন যে কোনও এক সময়ে, তার SetResultবা SetExceptionপদ্ধতিটিকে Task<T>তার Taskসম্পত্তির মাধ্যমে উন্মুক্তকরণটি সম্পূর্ণ করার জন্য বলা হচ্ছে ।

অন্য কথায়, এটি একটি Task<TResult>এবং এর সমাপ্তির জন্য প্রযোজক হিসাবে কাজ করে ।

আমি উদাহরণ এখানে দেখেছি :

অ্যাসিঙ্ক্রোনালিভাবে আমার একটি ফানক চালানোর কোনও উপায়ের প্রয়োজন এবং সেই ক্রিয়াকলাপটি উপস্থাপন করার জন্য কোনও টাস্ক লাগলে have

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

যা আমার কাছে না থাকলে * ব্যবহৃত হতে পারে Task.Factory.StartNew- তবে আমার কাছে আছে Task.Factory.StartNew

প্রশ্ন:

কেউ উদাহরণ দ্বারা সম্পর্কিত একটি দৃশ্যকল্প ব্যাখ্যা দয়া করে করতে পারেন সরাসরি করতে TaskCompletionSource একটি প্রয়োজন এবং না প্রকল্পিত যা আমার নেই অবস্থা Task.Factory.StartNew?


5
টাস্ক কমপ্লিশনসোর্সটি মূলত নতুন থ্রেড না করে টাস্কের সাথে ইভেন্ট ভিত্তিক async এপি মুড়ানোর জন্য ব্যবহৃত হয়।
আরভিস

উত্তর:


230

আমি সাধারণত এটি ব্যবহার করি যখন কেবলমাত্র ইভেন্ট ভিত্তিক এপিআই উপলব্ধ থাকে ( উদাহরণস্বরূপ উইন্ডোজ ফোন 8 সকেট ):

public Task<Args> SomeApiWrapper()
{
    TaskCompletionSource<Args> tcs = new TaskCompletionSource<Args>(); 

    var obj = new SomeApi();

    // will get raised, when the work is done
    obj.Done += (args) => 
    {
        // this will notify the caller 
        // of the SomeApiWrapper that 
        // the task just completed
        tcs.SetResult(args);
    }

    // start the work
    obj.Do();

    return tcs.Task;
}

সুতরাং এটি বিশেষত কার্যকর যখন সি # 5 asyncকীওয়ার্ডের সাথে একত্রে ব্যবহৃত হয় ।


4
আমরা কি এখানে দেখতে পাচ্ছি আপনি কথায় কথায় লিখতে পারেন? এটি SomeApiWrapperকি কোথাও অপেক্ষা করা হয়, প্রকাশকরা এই ইভেন্টটি উত্থাপন না করে এই কাজটি শেষ করার কারণ দেয়?
রই নমির

আমি স্রেফ যুক্ত হওয়া লিঙ্কটি একবার দেখুন
গেমসক্রিপশন

6
একটি আপডেট হিসাবে, মাইক্রোসফ্ট Microsoft.Bcl.Asyncন্যুগেটে প্যাকেজটি প্রকাশ করেছে যা async/await.NET 4.0 প্রকল্পের কীওয়ার্ডগুলিকে অনুমতি দেয় (ভিএস2012 এবং তার চেয়েও উচ্চতর প্রস্তাবিত)।
এরিক

1
@ Fran_gg7 আপনি একটি CancellationToken ব্যবহার করতে পারে, দেখুন msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx বা Stackoverflow উপর একটি নতুন প্রশ্ন এখানে
GameScripting

1
এই বাস্তবায়নে সমস্যাটি হ'ল এটি মেমরি ফাঁস সৃষ্টি করে কারণ ইভেন্টটি কখনই অবজেক্ট থেকে প্রকাশ হয় না D ডোন
ওয়াল্টার Vehoeven

78

আমার অভিজ্ঞতাগুলিতে, TaskCompletionSourceপুরানো অ্যাসিনক্রোনাস নিদর্শনগুলি আধুনিক async/awaitপ্যাটার্নে মোড়ানোর জন্য দুর্দান্ত ।

সবচেয়ে উপকারী উদাহরণটি আমি ভাবতে পারি এটি যখন কাজ করে তখন Socket। এটিতে পুরানো এপিএম এবং ইএপি নিদর্শন রয়েছে, তবে awaitable Taskযে পদ্ধতিগুলি TcpListenerএবং রয়েছে TcpClientতা নয়।

আমার ব্যক্তিগতভাবে NetworkStreamক্লাসের সাথে বেশ কয়েকটি সমস্যা আছে এবং কাঁচা পছন্দ করে Socket। এই async/awaitপ্যাটার্নটিও আমি পছন্দ করি তাই আমি একটি এক্সটেনশন ক্লাস SocketExtenderতৈরি করেছি যা এর জন্য বেশ কয়েকটি এক্সটেনশন পদ্ধতি তৈরি করে Socket

এই সমস্ত পদ্ধতিতে TaskCompletionSource<T>অ্যাসিনক্রোনাস কলগুলিকে মোড়ানোর জন্য ব্যবহার করা হয়:

    public static Task<Socket> AcceptAsync(this Socket socket)
    {
        if (socket == null)
            throw new ArgumentNullException("socket");

        var tcs = new TaskCompletionSource<Socket>();

        socket.BeginAccept(asyncResult =>
        {
            try
            {
                var s = asyncResult.AsyncState as Socket;
                var client = s.EndAccept(asyncResult);

                tcs.SetResult(client);
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
            }

        }, socket);

        return tcs.Task;
    }

আমি পাস socketমধ্যে BeginAcceptপদ্ধতি যাতে আমি কম্পাইলার স্থানীয় পরামিতি উত্তোলন হচ্ছে না বাইরে সামান্য কর্মক্ষমতা বুস্ট পেতে।

তারপরে এগুলির সমস্ত সৌন্দর্য:

 var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 listener.Bind(new IPEndPoint(IPAddress.Loopback, 2610));
 listener.Listen(10);

 var client = await listener.AcceptAsync();

1
টাস্ক.ফ্যাক্টরি.স্টার্টনিউ এখানে কাজ করবে না কেন?
তোলা ওদেজেয়

23
@ তোলা যেহেতু থ্রেডপুলের থ্রেডে চলমান একটি নতুন টাস্ক তৈরি করেছে, তবে উপরের কোডটি i / o সমাপ্তির থ্রেডটি বিগিনিএসেপ্ট দ্বারা শুরু করেছে, আইও: এটি কোনও নতুন থ্রেড শুরু করে না।
ফ্রান্সস বোমা

4
ধন্যবাদ, @ ফ্রান্সস-বোমা। সুতরাং টাস্ককম্পিশনসোর্স কোডটি রূপান্তর করার একটি সহজ উপায় যা ব্যবহার শুরু করুন ... সমাপ্তি ... বিবৃতিগুলিকে একটি কার্যে রূপান্তর করে?
তোলা ওদেজেয়

3
@ তোলাওদেজয়ী দেরিতে জবাব দেওয়ার একটি বিট, তবে হ্যাঁ এটির জন্য প্রাথমিক ব্যবহারের ক্ষেত্রে আমি এটি খুঁজে পেয়েছি। কোডের এই রূপান্তরটির জন্য এটি আশ্চর্যজনকভাবে কাজ করে।
এরিক

4
TaskFactory <TResult> .FromAsync মোড়ানো Begin.. End...বিবৃতি।
মাইকবিগ

37

আমার কাছে, ব্যবহারের জন্য একটি সর্বোত্তম দৃশ্যটি TaskCompletionSourceযখন সম্ভব হয় যখন আমার পদ্ধতিটি অগত্যা সময় সাপেক্ষ অপারেশন করতে হবে না । এটি আমাদের যা করতে দেয় তা হ'ল নির্দিষ্ট কেসগুলি নির্বাচন করা যেখানে আমরা একটি নতুন থ্রেড ব্যবহার করতে চাই।

এর জন্য একটি ভাল উদাহরণ হ'ল আপনি যখন ক্যাশে ব্যবহার করেন। আপনার কাছে এমন একটি GetResourceAsyncপদ্ধতি থাকতে পারে, যা অনুরোধ করা সংস্থানটির জন্য ক্যাশে নজর রাখে এবং যদি উত্সটি পাওয়া যায় তবে একবারে (নতুন থ্রেড ব্যবহার না করে TaskCompletionSource) ফেরত দেয় । কেবলমাত্র যদি সংস্থানটি পাওয়া যায় না, তবে আমরা একটি নতুন থ্রেড ব্যবহার করতে এবং এটি ব্যবহার করে পুনরুদ্ধার করতে চাই Task.Run()

একটি কোড উদাহরণ এখানে দেখা যায়: কীভাবে শর্তসাপেক্ষে কার্যগুলি অ্যাসিঙ্কনোলি চালাতে হয়


আমি আপনার প্রশ্ন এবং উত্তর দেখতে পেয়েছি। (উত্তরে আমার মন্তব্য দেখুন) .... :-) এবং প্রকৃতপক্ষে এটি একটি শিক্ষামূলক প্রশ্নোত্তর।
রই নমির

11
এটি আসলে এমন পরিস্থিতি নয় যেখানে টিসিএসের প্রয়োজন। আপনি এটি করতে সহজভাবে ব্যবহার Task.FromResultকরতে পারেন। অবশ্যই, আপনি 4.0 ব্যবহার করছেন এবং একটি না থাকে তাহলে Task.FromResultকি আপনার জন্য একটি TCS ব্যবহার করতে চাই হয় আপনার নিজের লেখা FromResult
পরিবেশন করুন

@ সার্ভিটি Task.FromResultকেবলমাত্র নেট 4.5 থেকে পাওয়া যায়। তার আগে এই আচরণটি অর্জনের উপায় ছিল।
আদি লেস্টার

@ অ্যাডিলেস্টার আপনি উত্তরটি উল্লেখ করছেন Task.Run, এটি ইঙ্গিত করছে এটি 4.5+ 4.5 এবং আমার পূর্ববর্তী মন্তব্য বিশেষভাবে। নেট 4.0।
পরিবেশন করুন

@ সার্ভি এই উত্তরটি পড়ছেন এমন সবাই লক্ষ্যবস্তু নয় N নেট 4.5। আমি বিশ্বাস করি এটি একটি ভাল এবং বৈধ উত্তর যা লোকদের ওপির প্রশ্ন জিজ্ঞাসা করতে সহায়তা করে (যা উপায় দ্বারা ট্যাগ করা হয় (নেট -৪.০))। যে কোনও উপায়ে, ডাউনভোটিংটি আমার কাছে কিছুটা বেশি মনে হয় তবে আপনি যদি সত্যই বিশ্বাস করেন যে এটি ডাউন ডাউনের প্রাপ্য তবে আপনি এগিয়ে যান।
আদি লেস্টার

25

ইন এই ব্লগ পোস্টে , লেভি Botelho বর্ণনা কিভাবে ব্যবহার করার জন্য TaskCompletionSourceএকটি প্রক্রিয়া আপনি এটা আরম্ভ এবং তার পরিসমাপ্তি অপেক্ষা করতে যেমন জন্য একটি অ্যাসিঙ্ক্রোনাস মোড়কের লিখতে।

public static Task RunProcessAsync(string processPath)
{
    var tcs = new TaskCompletionSource<object>();
    var process = new Process
    {
        EnableRaisingEvents = true,
        StartInfo = new ProcessStartInfo(processPath)
        {
            RedirectStandardError = true,
            UseShellExecute = false
        }
    };
    process.Exited += (sender, args) =>
    {
        if (process.ExitCode != 0)
        {
            var errorMessage = process.StandardError.ReadToEnd();
            tcs.SetException(new InvalidOperationException("The process did not exit correctly. " +
                "The corresponding error message was: " + errorMessage));
        }
        else
        {
            tcs.SetResult(null);
        }
        process.Dispose();
    };
    process.Start();
    return tcs.Task;
}

এবং এর ব্যবহার

await RunProcessAsync("myexecutable.exe");

14

দেখে মনে হচ্ছে কারও উল্লেখ করা হয়নি, তবে আমার ধারণা ইউনিট পরীক্ষাগুলিও সত্যিকারের জীবনকে যথেষ্ট বলে বিবেচিত হতে পারে ।

TaskCompletionSourceঅ্যাসিঙ্ক পদ্ধতিতে নির্ভরতা উপহাস করার সময় আমি দরকারী বলে মনে করি ।

পরীক্ষার অধীনে প্রকৃত প্রোগ্রামে:

public interface IEntityFacade
{
  Task<Entity> GetByIdAsync(string id);
}

ইউনিট পরীক্ষায়:

// set up mock dependency (here with NSubstitute)

TaskCompletionSource<Entity> queryTaskDriver = new TaskCompletionSource<Entity>();

IEntityFacade entityFacade = Substitute.For<IEntityFacade>();

entityFacade.GetByIdAsync(Arg.Any<string>()).Returns(queryTaskDriver.Task);

// later on, in the "Act" phase

private void When_Task_Completes_Successfully()
{
  queryTaskDriver.SetResult(someExpectedEntity);
  // ...
}

private void When_Task_Gives_Error()
{
  queryTaskDriver.SetException(someExpectedException);
  // ...
}

সর্বোপরি, টাস্ক কমপ্লিশনসোর্সের এই ব্যবহারটিকে "এমন একটি টাস্ক অবজেক্ট যা কোড চালায় না" এর আর একটি ঘটনা মনে হয়।


11

টাস্ক কমপ্লিশনসোর্সটি টাস্ক অবজেক্টগুলি তৈরি করতে ব্যবহৃত হয় যা কোড চালায় না। বাস্তব বিশ্বের পরিস্থিতিতে, টাস্ক কমপ্লিশনসোর্স I / O বাউন্ড অপারেশনের জন্য আদর্শ। এইভাবে, আপনি ক্রিয়াকলাপের সময়কালের জন্য কোনও থ্রেড অবরুদ্ধ না করে কর্মের সমস্ত সুবিধা (যেমন রিটার্ন মান, ধারাবাহিকতা ইত্যাদি) পান। যদি আপনার "ফাংশন" আই / ও বাউন্ড অপারেশন হয় তবে নতুন টাস্কটি ব্যবহার করে কোনও থ্রেড ব্লক করার পরামর্শ দেওয়া হয় না । পরিবর্তে, TaskCompletionSource ব্যবহার করে , আপনি যখন I / O বাউন্ড অপারেশনটি শেষ করেন বা ত্রুটিগুলি দেখান তখনই আপনি একটি স্লেভ টাস্ক তৈরি করতে পারেন।


5

"নেট সমান্তরাল প্রোগ্রামিং উইথ। নেট" ব্লগ থেকে এই পোস্টে একটি শালীন ব্যাখ্যা সহ একটি বাস্তব বিশ্বের উদাহরণ রয়েছে । আপনার সত্যই এটি পড়া উচিত, তবে যাইহোক এখানে একটি সংক্ষিপ্তসার এখানে।

ব্লগ পোস্টটি এর জন্য দুটি বাস্তবায়ন দেখায়:

"" বিলম্বিত "কাজগুলি তৈরির জন্য একটি ফ্যাক্টরি পদ্ধতি, যা কিছু ব্যবহারকারী দ্বারা সরবরাহিত সময়সীমা না আসা পর্যন্ত আসলে নির্ধারিত হয় না।"

প্রদর্শিত প্রথম বাস্তবায়ন ভিত্তিক Task<>এবং দুটি বড় ত্রুটি রয়েছে। দ্বিতীয় বাস্তবায়ন পোস্ট ব্যবহার করে এগুলি প্রশমিত করতে চলেছে TaskCompletionSource<>

দ্বিতীয় যে বাস্তবায়ন এখানে:

public static Task StartNewDelayed(int millisecondsDelay, Action action)
{
    // Validate arguments
    if (millisecondsDelay < 0)
        throw new ArgumentOutOfRangeException("millisecondsDelay");
    if (action == null) throw new ArgumentNullException("action");

    // Create a trigger used to start the task
    var tcs = new TaskCompletionSource<object>();

    // Start a timer that will trigger it
    var timer = new Timer(
        _ => tcs.SetResult(null), null, millisecondsDelay, Timeout.Infinite);

    // Create and return a task that will be scheduled when the trigger fires.
    return tcs.Task.ContinueWith(_ =>
    {
        timer.Dispose();
        action();
    });
}

tcs.Task এ অপেক্ষা করা এবং তারপরে অ্যাকশন () এর পরে ব্যবহার করা ভাল
রয়ী নমির

5
আপনি যে প্রসঙ্গে চলে গিয়েছিলেন সেখানে ফিরে গেছেন, যেখানে চালিয়ে যাওয়া প্রসঙ্গে প্রসঙ্গটি সংরক্ষণ করে না। (ডিফল্টরূপে নয়) এছাড়াও যদি ক্রিয়াকলাপের পরবর্তী বিবৃতিটি () ব্যতিক্রম ঘটায়, সেখানে অপেক্ষা করা শক্ত হবে যেখানে অপেক্ষারত ব্যবহার আপনাকে নিয়মিত ব্যতিক্রম হিসাবে দেখায়।
রই নমির

3
কেন কেবল await Task.Delay(millisecondsDelay); action(); return;বা (নেট নেট return Task.Delay(millisecondsDelay).ContinueWith( _ => action() );
in.০

@ স্পেনজ্যাগন যা পড়া এবং বজায় রাখা অবশ্যই সহজ হবে
JwJosefy

@ জেজেজেফি প্রকৃতপক্ষে, টাস্ক.ডলে পদ্ধতিটি উপরের কোডের মতোই, টাস্ক কমপ্লিটসোর্স ব্যবহার করে প্রয়োগ করা যেতে পারে । আসল বাস্তবায়নটি এখানে: Task.cs
sgnsajgon

4

এটি জিনিসগুলিকে বড় করে দেখানো হতে পারে তবে টাস্ক কমপ্লেশন উত্সটি একটি ইভেন্টে অপেক্ষা করার অনুমতি দেয়। যেহেতু টিসিএস.সেটরসাল্ট কেবল ইভেন্টটি হয়ে যাওয়ার পরে সেট করা থাকে, তাই কলার সেই কাজের জন্য অপেক্ষা করতে পারে।

আরও অন্তর্দৃষ্টি জন্য এই ভিডিওটি দেখুন:

http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Lucian03-TipsForAsyncThreadsAndDatabinding


1
দয়া করে এখানে প্রাসঙ্গিক কোড বা ডকুমেন্টেশন রাখুন কারণ লিঙ্কগুলি সময়ের সাথে সাথে এই উত্তরটি অপ্রাসঙ্গিক করতে পারে।
রোফোনাল

3

TaskCompletionSourceডাউনলোডের সারিতে বাস্তবায়ন করার সময় আমি আসল বিশ্বের পরিস্থিতি । আমার ক্ষেত্রে যদি ব্যবহারকারী 100 টি ডাউনলোড শুরু করে তবে আমি এগুলি একবারে বরখাস্ত করতে চাই না এবং তাই কোনও স্ট্র্রেড টাস্ক ফিরিয়ে না দিয়ে আমি যুক্ত কোনও টাস্কটি ফিরিয়ে দেব TaskCompletionSource। ডাউনলোড একবার থ্রেডটি সম্পন্ন করে যা সারিতে কাজ করছে তা কাজটি সম্পূর্ণ করে।

এখানে মূল ধারণাটি হ'ল আমি যখন ডায়লপ করছি তখন যখন কোনও ক্লায়েন্ট কোনও কাজটি শুরু করতে বলে যখন এটি আসলে শুরু হয়। এই ক্ষেত্রে কারণ আমি চাই না ক্লায়েন্টকে রিসোর্স ম্যানেজমেন্টের সাথে ডিল করতে হবে।

দয়া করে মনে রাখবেন আপনি ব্যবহার করতে পারেন ASYNC / অপেক্ষায় রয়েছেন মধ্যে .net 4 যতদিন আপনি একটি সি # 5 কম্পাইলার (বনাম 2012+) দেখতে ব্যবহার করছেন এখানে আরো বিস্তারিত জানার জন্য।


0

TaskCompletionSourceএটি বাতিল না হওয়া পর্যন্ত আমি একটি টাস্ক চালিয়েছি। এক্ষেত্রে এটি কোনও সার্ভিসবাসীর গ্রাহক যেটি আমি সাধারণত চালাতে চাই যতক্ষণ অ্যাপ্লিকেশন চলে run

public async Task RunUntilCancellation(
    CancellationToken cancellationToken,
    Func<Task> onCancel)
{
    var doneReceiving = new TaskCompletionSource<bool>();

    cancellationToken.Register(
        async () =>
        {
            await onCancel();
            doneReceiving.SetResult(true); // Signal to quit message listener
        });

    await doneReceiving.Task.ConfigureAwait(false); // Listen until quit signal is received.
}

1
ব্যবহারের কোন প্রয়োজন নেই 'ASYNC' '-এর সাথে TaskCompletionSource' হিসেবে এটি আগে থেকেই একটি টাস্ক সৃষ্টি করেছেন
Mandeep জানজুয়া

-1

TaskCompletionSourceWaitHandleথ্রেড হিসাবে টাস্ক হয় । এবং তাই আমরা TaskCompletionSource সঠিক সংকেত সম্পাদন করতে ব্যবহার করতে পারি ।

একটি উদাহরণ এই প্রশ্নের আমার উত্তর: ঠিক আছে ক্লিক করার পরে কন্টেন্টডায়ালগ বিলম্ব

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