আগুন নেওয়ার সহজ উপায় এবং সি # 4.0 তে পদ্ধতি ভুলে যাওয়া


106

আমি এই প্রশ্নটি সত্যিই পছন্দ করি:

আগুন নেওয়ার সহজ উপায় এবং সি # তে পদ্ধতিটি ভুলে যাবেন?

আমি কেবল জানতে চাই যে এখন সি # ৪.০ এ আমাদের সমান্তরাল এক্সটেনশান রয়েছে কি সমান্তরাল লিংকের সাথে ফায়ার এবং ভুলে যাওয়ার আরও ভাল ক্লিনার কোন উপায় আছে?


4
এই প্রশ্নের উত্তর এখনও .NET 4.0 এ প্রযোজ্য। কুইউউজার ওয়ার্ক আইটেমের চেয়ে ফায়ার এবং ভুলেও খুব সহজ কিছু পায় না।
ব্রায়ান রাসমুসেন

উত্তর:


116

৪.০ এর কোনও উত্তর নয়, তবে এটি লক্ষণীয় .. নেট ৪.৫ আপনি এটিকে আরও সহজ করে তুলতে পারেন:

#pragma warning disable 4014
Task.Run(() =>
{
    MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014

প্রগমা হ'ল সতর্কতাটি অক্ষম করা যা আপনাকে বলে যে আপনি এই কার্যটিকে আগুন হিসাবে চালাচ্ছেন এবং ভুলে যাচ্ছেন।

যদি কোঁকড়া ধনুর্বন্ধনী এর ভিতরে পদ্ধতিটি একটি কার্য ফেরত দেয়:

#pragma warning disable 4014
Task.Run(async () =>
{
    await MyFireAndForgetMethod();
}).ConfigureAwait(false);
#pragma warning restore 4014

আসুন এটি ভেঙে দিন:

টাস্ক.রুন একটি টাস্ক ফেরত দেয়, যা একটি সংকলক সতর্কতা উত্পন্ন করে (CS4014 সতর্ক করে) উল্লেখ করে যে এই কোডটি পটভূমিতে চালিত হবে - এটি আপনি যা চেয়েছিলেন ঠিক তাই, তাই আমরা সতর্কতা 4040 অক্ষম করে দিয়েছি।

ডিফল্টরূপে, টাস্কগুলি "মার্শালটিকে মূল মূল থ্রেডে ফিরে যেতে" চেষ্টা করে যার অর্থ এই টাস্কটি পটভূমিতে চলবে, তারপরে এটি শুরু হওয়া থ্রেডে ফিরে আসার চেষ্টা করবে। আসল থ্রেডটি শেষ হওয়ার পরে প্রায়শই গুলি চালান এবং ভুলে যান এটি থ্রেডঅবর্টেক্সপশন নিক্ষেপ করবে। বেশিরভাগ ক্ষেত্রে এটি নিরীহ - এটি কেবল আপনাকে বলছে, আমি আবার যোগদানের চেষ্টা করেছি, আমি ব্যর্থ হয়েছি, তবে আপনি যাইহোক যত্ন নেন না। তবে প্রোডাকশনে আপনার লগগুলিতে বা স্থানীয় দেবের ডিবাগারে থ্রেডআবার্টএক্সপ্যাজেসন পাওয়া এখনও খানিকটা গোলমাল।.ConfigureAwait(false)পরিপাটি থাকা এবং স্পষ্টভাবে বলতে চাওয়ার এক উপায়, এটি ব্যাকগ্রাউন্ডে চালান, এবং এটিই।

যেহেতু এটি শব্দযুক্ত, বিশেষত কুৎসিত প্রগমা, আমি এটির জন্য একটি লাইব্রেরি পদ্ধতি ব্যবহার করি:

public static class TaskHelper
{
    /// <summary>
    /// Runs a TPL Task fire-and-forget style, the right way - in the
    /// background, separate from the current thread, with no risk
    /// of it trying to rejoin the current thread.
    /// </summary>
    public static void RunBg(Func<Task> fn)
    {
        Task.Run(fn).ConfigureAwait(false);
    }

    /// <summary>
    /// Runs a task fire-and-forget style and notifies the TPL that this
    /// will not need a Thread to resume on for a long time, or that there
    /// are multiple gaps in thread use that may be long.
    /// Use for example when talking to a slow webservice.
    /// </summary>
    public static void RunBgLong(Func<Task> fn)
    {
        Task.Factory.StartNew(fn, TaskCreationOptions.LongRunning)
            .ConfigureAwait(false);
    }
}

ব্যবহার:

TaskHelper.RunBg(async () =>
{
    await doSomethingAsync();
}

7
@ksm আপনার দৃষ্টিভঙ্গি দুর্ভাগ্যক্রমে কিছু সমস্যার জন্য রয়েছে - আপনি কি এটি পরীক্ষা করেছেন? সেই পদ্ধতির কারণ হ'ল সতর্কতা 4014 উপস্থিত রয়েছে। অ্যাসিঙ্ক পদ্ধতিটি অপেক্ষা না করে এবং টাস্ক.রুনের সাহায্য ছাড়াই কল করা ... সেই পদ্ধতিটি চালানোর কারণ হবে, হ্যাঁ, তবে এটি শেষ হয়ে গেলে এটি মার্শালটিকে মূল থ্রেড থেকে ফিরিয়ে দেওয়ার চেষ্টা করবে যেখান থেকে তা বরখাস্ত করা হয়েছিল। প্রায়শই সেই থ্রেড ইতিমধ্যে কার্যকর হয়ে যায় এবং আপনার কোডটি বিভ্রান্তিকর, অনির্দিষ্টকীয় উপায়ে বিস্ফোরিত হবে। এটা করবেন না! টাস্ক.রুনের কাছে কলটি "বৈশ্বিক পরিপ্রেক্ষিতে এটি চালান" বলার সুবিধাজনক উপায়, এটি মার্শাল করার চেষ্টা করার জন্য কিছুই রাখেনি।
ক্রিস মোসচিনি

4
@ ক্রিসমোসচিনি সাহায্য করতে পেরে আনন্দিত, এবং আপডেটের জন্য ধন্যবাদ! অন্যদিকে, যেখানে আমি উপরের মন্তব্যে "আপনি এটি একটি অ্যাসিঙ্ক বেনামে ফানক দিয়ে ডাকছেন" লিখেছেন, এটি সত্যিই আমার কাছে বিভ্রান্তিকর যা সত্য। আমি কেবল জানি কোডটি কাজ করে যখন অ্যাসিঙ্কটি কলিং (বেনামে ফাংশন) কোডটিতে অন্তর্ভুক্ত করা হয় না, তবে তার অর্থ কি কলিং কোডটি একটি অ্যাসিঙ্ক্রোনাস পদ্ধতিতে চালিত হবে না (যা খারাপ, খুব খারাপ গোচা)? সুতরাং আমি অ্যাসিঙ্ক ছাড়া সুপারিশ করছি না , এটি কেবল অদ্ভুত যে এই ক্ষেত্রে, উভয়ই কাজ করে।
নিকোলাস পিটারসেন

8
আমি বিন্দু দেখতে না ConfigureAwait(false)উপর Task.Runযখন আপনি না awaitকাজ। ফাংশনটির উদ্দেশ্য এর নামে: " অপেক্ষা করুন কনফিগার করুন "। আপনি যদি awaitকাজটি না করেন তবে আপনি একটি ধারাবাহিকতা নিবন্ধভুক্ত করবেন না এবং আপনি যেমন বলছেন তেমন কোনও কাজের জন্য "মূল থ্রেডে মার্শাল" করার কোনও কোড নেই। চূড়ান্তকরণকারী থ্রেডে পুনরায় উত্থাপিত হওয়ার পরে আরও বড় ঝুঁকি হ'ল, যা এই উত্তরটিও সম্বোধন করে না।
মাইক স্ট্রোবেল

4
@stricq এখানে কোনও অ্যাসিঙ্ক শূন্য ব্যবহার নেই। যদি আপনি async () => ... এর উল্লেখ করছেন তবে ... স্বাক্ষরটি এমন একটি ফানক যা কোনও টাস্ককে শূন্য করে না, বাতিল করে না।
ক্রিস মোসচিনি

4
সতর্কতা দমন করতে ভিবি.এন.এতে:#Disable Warning BC42358
আলটিস্তানো জেরুং

86

সঙ্গে Taskবর্গ হ্যাঁ, কিন্তু PLINQ সংগ্রহের উপর অনুসন্ধান জন্য সত্যিই হয়।

নীচের মতো কিছু এটি টাস্কের সাহায্যে করবে।

Task.Factory.StartNew(() => FireAway());

অথবা এমনকি...

Task.Factory.StartNew(FireAway);

বা ...

new Task(FireAway).Start();

কোথায় FireAway আছে

public static void FireAway()
{
    // Blah...
}

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

ThreadPool.QueueUserWorkItem(o => FireAway());

অবশ্যই তারা যদিও কার্যকারিতা সমতুল্য না?
জোনাথন ক্রেসনার

6
স্টার্টনিউ এবং নতুন টাস্ক.স্টার্টের মধ্যে একটি সূক্ষ্ম অর্থগত পার্থক্য রয়েছে তবে অন্যথায়, হ্যাঁ। থ্রেডপুলের একটি থ্রেডে চালানোর জন্য তারা সকলেই ফায়ারওয়ে সারি করে।
অ্যাডি মিলার

এই ক্ষেত্রে জন্য কাজ: fire and forget in ASP.NET WebForms and windows.close()?
প্রিগ্যান্টকোজোনিরো ক্যাব্রন

34

এই প্রশ্নের অগ্রণী উত্তর নিয়ে আমার কয়েকটি সমস্যা রয়েছে।

প্রথমত, একটি সত্য আগুন এবং ভুলে যাওয়া পরিস্থিতিতে, আপনি সম্ভবত awaitটাস্কটি করবেন না , তাই সংযোজন করা অযথা ConfigureAwait(false)। আপনি যদি awaitমানটি না দিয়ে দেনConfigureAwait , তবে সম্ভবত এটির কোনও প্রভাব থাকতে পারে না।

দ্বিতীয়ত, যখন টাস্কটি একটি ব্যতিক্রম পূর্ণ করে তখন কী হয় তা সম্পর্কে আপনার সচেতন হওয়া দরকার। @ অ্যাড-মিলার প্রস্তাবিত সহজ সমাধানটি বিবেচনা করুন:

Task.Factory.StartNew(SomeMethod);  // .NET 4.0
Task.Run(SomeMethod);               // .NET 4.5

এটি একটি বিপত্তির পরিচয় দেয়: যদি একটি অপরিবর্তিত ব্যতিক্রম এড়ায় SomeMethod(), তবে সে ব্যতিক্রম কখনও পর্যবেক্ষণ করা হবে না এবং আপনার অ্যাপ্লিকেশনটি ক্র্যাশ করে 1 টি চূড়ান্তকরণকারী থ্রেডে পুনর্বিবেচনা করা হতে পারে। অতএব, ফলস্বরূপ যে কোনও ব্যতিক্রম পরিলক্ষিত হচ্ছে তা নিশ্চিত করতে আমি কোনও সহায়ক পদ্ধতি ব্যবহার করার পরামর্শ দেব recommend

আপনি এই জাতীয় কিছু লিখতে পারেন:

public static class Blindly
{
    private static readonly Action<Task> DefaultErrorContinuation =
        t =>
        {
            try { t.Wait(); }
            catch {}
        };

    public static void Run(Action action, Action<Exception> handler = null)
    {
        if (action == null)
            throw new ArgumentNullException(nameof(action));

        var task = Task.Run(action);  // Adapt as necessary for .NET 4.0.

        if (handler == null)
        {
            task.ContinueWith(
                DefaultErrorContinuation,
                TaskContinuationOptions.ExecuteSynchronously |
                TaskContinuationOptions.OnlyOnFaulted);
        }
        else
        {
            task.ContinueWith(
                t => handler(t.Exception.GetBaseException()),
                TaskContinuationOptions.ExecuteSynchronously |
                TaskContinuationOptions.OnlyOnFaulted);
        }
    }
}

এই বাস্তবায়নটির ন্যূনতম ওভারহেড থাকা উচিত: যদি কাজটি সফলভাবে শেষ না হয় তবে ধারাবাহিকতা চালিত হয় এবং এটি সমলয়ভাবে আহ্বান করা উচিত (মূল কাজ থেকে পৃথকভাবে নির্ধারিত হওয়ার বিপরীতে)। "অলস" ক্ষেত্রে, আপনি এমনকি ধারাবাহিক প্রতিনিধিদের জন্য বরাদ্দও ব্যয় করতে পারবেন না।

একটি অ্যাসিনক্রোনাস অপারেশন চালু করা তুচ্ছ হয়ে যায়:

Blindly.Run(SomeMethod);                              // Ignore error
Blindly.Run(SomeMethod, e => Log.Warn("Whoops", e));  // Log error

১। নেট 4.0.০ এ ডিফল্ট আচরণ ছিল। .NET 4.5-এ, ডিফল্ট আচরণটি এমনভাবে পরিবর্তন করা হয়েছিল যে অননक्षित সংরক্ষিত ব্যতিক্রমগুলি চূড়ান্তকরণকারী থ্রেডে পুনরায় আরম্ভ করা হবে না (যদিও আপনি এখনও এগুলি টাস্কশেডুলারের অনাবৃত টাস্ক এক্সপশন ইভেন্টের মাধ্যমে পর্যবেক্ষণ করতে পারেন)। যাইহোক, ডিফল্ট কনফিগারেশন ওভাররাইড করা যেতে পারে এবং আপনার অ্যাপ্লিকেশনটি .NET 4.5 প্রয়োজন থাকলেও, আপনার ধরে নেওয়া উচিত নয় যে অনাবৃত টাস্ক ব্যতিক্রমগুলি নিরীহ হবে।


4
যদি কোনও হ্যান্ডলারটি পাস হয়ে যায় এবং ContinueWithবাতিল হওয়ার কারণে অনুরোধ করা হয়, তবে পূর্বসূরির ব্যতিক্রম সম্পত্তি নাল হবে এবং একটি নাল রেফারেন্স ব্যতিক্রম নিক্ষেপ করা হবে। টাস কন্টিনিউশন অপশনে সেট করা OnlyOnFaultedনাল চেকের প্রয়োজনীয়তা দূর করবে বা এটি ব্যবহারের আগে ব্যতিক্রমটি শূন্য রয়েছে কিনা তা পরীক্ষা করবে।
sanmcp

রান () পদ্ধতিটি বিভিন্ন পদ্ধতির স্বাক্ষরের জন্য ওভাররাইড করা দরকার। টাস্কের এক্সটেনশন পদ্ধতি হিসাবে এটি করা ভাল।
stricq

4
@ স্ট্রিকক "ফায়ার এন্ড ভুলে" অপারেশন সম্পর্কে প্রশ্ন জিজ্ঞাসা করেছিল (যেমন, স্ট্যাটাস কখনই চেক হয় না এবং ফলাফল কখনই পর্যবেক্ষণ হয় না), তাই এটিই আমি মনোনিবেশ করেছি। যখন প্রশ্নটি হয় কীভাবে সবচেয়ে পরিষ্কারভাবে নিজেকে পায়ে গুলি করা যায়, তবে কোনও সমাধানটি কোনও ডিজাইনের দৃষ্টিকোণ থেকে "আরও ভাল" হয় তা নিয়ে বিতর্ক করা বরং মোটা হয়ে যায় :)। দ্যসেরা উত্তর তর্কসাপেক্ষে হল "না", কিন্তু যে ন্যূনতম উত্তর দৈর্ঘ্যের হিংস্র সংক্ষিপ্ত, তাই আমি একটি সংক্ষিপ্ত সমাধান এড়াতে বিষয় অন্যান্য উত্তর উপস্থাপন প্রদানের উপর দৃষ্টি নিবদ্ধ। যুক্তিগুলি সহজেই একটি বন্ধের সাথে আবৃত হয় এবং কোনও ফেরতের মূল্য না দিয়ে ব্যবহার করে Taskপ্রয়োগের বিশদ হয়ে যায়।
মাইক স্ট্রোবেল

@ স্ট্রিকق বলেছেন যে, আমি আপনার সাথে একমত নই। আপনার প্রস্তাবিত বিকল্পটি হ'ল বিভিন্ন কারণে হলেও অতীতে আমি যা করেছি তা হ'ল। "আমি কোনও অ্যাপ্লিকেশন ক্রাশ করা এড়াতে চাই যখন কোনও বিকাশকারী কোনও ত্রুটি পর্যবেক্ষণ করতে ব্যর্থ হয় Task" এইরকম নয় "আমি কোনও ব্যাকগ্রাউন্ড অপারেশন শুরু করার সহজ উপায় চাই, তার ফলাফলটি কখনই পর্যবেক্ষণ করি না, এবং কোন পদ্ধতিটি ব্যবহার করা হয় তা আমি যত্ন করি না don't এটা করতে। " সেই ভিত্তিতে আমি আমার উত্তরের পিছনে দাঁড়িয়ে আছি যে প্রশ্ন জিজ্ঞাসা করা হয়েছিল
মাইক স্ট্রোবেল

এই ক্ষেত্রে কাজ করা: fire and forget মধ্যে ASP.NET ওয়েবফর্মগুলি এবং windows.close()?
PreguntonCojoneroCabrón

7

মাইক স্ট্রোবেলের উত্তরের সাথে ঘটতে পারে এমন কিছু সমস্যা সমাধান করার জন্য:

আপনি যদি সেই কাজে ব্যবহার করে var task = Task.Run(action)এবং ধারাবাহিকতা নির্ধারণ করেন, তবে আপনি Taskব্যতিক্রম হ্যান্ডলার ধারাবাহিকতাটি নির্ধারণ করার আগে আপনি কিছু ব্যতিক্রম ছুঁড়ে ফেলার ঝুঁকিতে পড়বেন Task। সুতরাং, নীচের শ্রেণিগুলি এই ঝুঁকি থেকে মুক্ত হওয়া উচিত:

using System;
using System.Threading.Tasks;

namespace MyNameSpace
{
    public sealed class AsyncManager : IAsyncManager
    {
        private Action<Task> DefaultExeptionHandler = t =>
        {
            try { t.Wait(); }
            catch { /* Swallow the exception */ }
        };

        public Task Run(Action action, Action<Exception> exceptionHandler = null)
        {
            if (action == null) { throw new ArgumentNullException(nameof(action)); }

            var task = new Task(action);

            Action<Task> handler = exceptionHandler != null ?
                new Action<Task>(t => exceptionHandler(t.Exception.GetBaseException())) :
                DefaultExeptionHandler;

            var continuation = task.ContinueWith(handler,
                TaskContinuationOptions.ExecuteSynchronously
                | TaskContinuationOptions.OnlyOnFaulted);
            task.Start();

            return continuation;
        }
    }
}

এখানে, taskসরাসরি চালানো হয় না, পরিবর্তে এটি তৈরি করা হয়, একটি ধারাবাহিকতা বরাদ্দ করা হয়, এবং কেবল তখনই ধারাবাহিকতা নির্ধারণের আগে কার্য সম্পাদন (বা কিছু ব্যতিক্রম ছুঁড়ে দেওয়া) সম্পন্ন করার ঝুঁকি দূর করার জন্য টাস্কটি চালানো হয়।

এখানে Runপদ্ধতিটি ধারাবাহিকতাটি ফিরিয়ে দেয় Taskতাই আমি কার্যকর হয়ে গেছে কিনা তা নিশ্চিত করে ইউনিট পরীক্ষা লিখতে সক্ষম হয়েছি। যদিও আপনি আপনার ব্যবহারের ক্ষেত্রে এটি নিরাপদে উপেক্ষা করতে পারেন।


এটাও কি ইচ্ছাকৃত যে আপনি এটিকে একটি স্ট্যাটিক ক্লাস করেননি?
ডিয়ান্টও

এই শ্রেণিটি IAsyncManager ইন্টারফেস প্রয়োগ করে, সুতরাং এটি স্ট্যাটিক শ্রেণি হতে পারে না।
Mert আক্কায়া

আমি মনে করি না যে পরিস্থিতিটি এই বিষয়টির দিকে মনোযোগ দিচ্ছে (ধারাবাহিকতা যুক্ত হওয়ার আগে টাস্ক ত্রুটিগুলি) গুরুত্বপূর্ণ। যদি এটি ঘটে ত্রুটিযুক্ত অবস্থা এবং ব্যতিক্রমটি কার্যটিতে সঞ্চিত থাকে এবং এটি সংযুক্ত হওয়ার পরে ধারাবাহিকতা দ্বারা পরিচালিত হবে। বুঝতে গুরুত্বপূর্ণ পয়েন্ট যে ব্যতিক্রম একটি অপেক্ষায় রয়েছেন টাস্ক পর্যন্ত নিক্ষিপ্ত নয় / task.Wait () / task.Result / task.GetAwaiter () GetResult () -। দেখতে docs.microsoft.com/en-us/dotnet/ স্ট্যান্ডার্ড / সমান্তরাল প্রোগ্রামিং /…
রাইস জোনস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.