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


150

আমি ডাব্লুসিএফ-তে দেখেছি তাদের [OperationContract(IsOneWay = true)]বৈশিষ্ট্যটি রয়েছে। তবে ডাব্লুসিএফ কেবল একটি নন-ব্লকিং কার্য তৈরি করতে ধীর এবং ভারী ধরণের বলে মনে হচ্ছে। আদর্শভাবে স্থির অকার্যকর ননব্লকিংয়ের মতো কিছু থাকবে MethodFoo(){}তবে আমি মনে করি না এটি বিদ্যমান exists

সি # তে নন-ব্লকিং পদ্ধতি কল তৈরির দ্রুততম উপায় কী?

যেমন

class Foo
{
    static void Main()
    {
        FireAway(); //No callback, just go away
        Console.WriteLine("Happens immediately");
    }

    static void FireAway()
    {
        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("5 seconds later");
    }
}

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

উত্তর:


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

(পাঁচ বছর পর...)

Task.Run(() => FireAway());

luisperezphd দ্বারা চিহ্নিত হিসাবে


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

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

3
চালানোর গ্যারান্টিযুক্ত নন-ব্লকিং পদ্ধতি কল করার কোনও উপায় নেই, সুতরাং এটি আসলে আইএমও প্রশ্নের সবচেয়ে সঠিক উত্তর। যদি আপনাকে মৃত্যুদণ্ডের গ্যারান্টি দিতে হয় তবে অটোসেটসেন্ট (কেভ হিসাবে উল্লেখ করা হয়েছে) এর মতো নিয়ন্ত্রণ কাঠামোর মাধ্যমে সম্ভাব্য ব্লকিং চালু করা দরকার
গুভান্তে

1
থ্রেড পুলে স্বাধীনভাবে কোনও থ্রেডে টাস্কটি চালাতে, আমি বিশ্বাস করি (new Action(FireAway)).BeginInvoke()
আপনিও

2
Task.Factory.StartNew(() => myevent());উত্তরের স্ট্যাকওভারফ্লো.com
লুইস পেরেজ

39

সি # 4.0 এবং আরও নবীনতরদের জন্য, এটি আমাকে আঘাত করে যে সর্বোত্তম উত্তরটি এখন এডি মিলার এখানে দিয়েছেন: আগুন করার সহজ উপায় এবং সি # 4.0 তে পদ্ধতি ভুলে যাওয়া

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

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

Task.Factory.StartNew(FireAway);

অথবা ...

new Task(FireAway).Start();

কোথায় FireAwayআছে

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

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

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

11
আমি ভাল প্রশ্নের ভাল উত্তর সহজেই পাওয়া সবচেয়ে আগ্রহী। আমি অবশ্যই অন্যকেও এটি করতে উত্সাহিত করব।
প্যাট্রিক জাজালাপস্কি

3
স্ট্যাকওভারফ্লো / শেল্প / রেফারেন্সিং অনুসারে , আপনি অন্য উত্স থেকে উদ্ধৃতি দিচ্ছেন তা বোঝাতে আপনাকে ব্লককোটগুলি ব্যবহার করতে হবে। এটি হিসাবে আপনার উত্তরটি আপনার নিজের সমস্ত কাজ বলে মনে হয়। উত্তরের হুবহু কপিটি পুনরায় পোস্ট করার মাধ্যমে আপনার অভিপ্রায় একটি মন্তব্যে একটি লিঙ্ক দিয়ে অর্জন করা যেতে পারে।
টম

1
কিভাবে পরামিতি পাস FireAway?
গাইড

আমি বিশ্বাস করি আপনি যদি প্রথম সমাধান ব্যবহার করতে হবে চাই: Task.Factory.StartNew(() => FireAway(foo));
প্যাট্রিক জাজালাপস্কি

1
Task.Factory.StartNew(() => FireAway(foo));
ফু

22

নেট 4.5 এর জন্য:

Task.Run(() => FireAway());

15
Fyi, এটি ব্লগস.এমএসএনTask.Factory.StartNew(() => FireAway(), CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
জিম

2
জেনে রাখা ভাল, @ জিমজার্স!
ডেভিড মারডোক

উত্তরোত্তর স্বার্থে, তাদের মন্তব্যে @ জিমগার্টস যুক্ত লিখিত নিবন্ধটি এখন 404'd (ধন্যবাদ, এমএস!)। সেই ইউআরএলটিতে তারিখের স্ট্যাম্প
ড্যান অ্যাটকিনসন

1
@ ডান অ্যাটকিনসন আপনি সঠিক আছেন এখানে আর্কাইভ.আরজে আসলটি রয়েছে, ঠিক এমএস যদি আবার এটিকে সরিয়ে দেয়: web.archive.org/web/20160226022029/http://blogs.msdn.com/b/…
ডেভিড

18

উইলের উত্তরে যুক্ত করতে , এটি যদি কোনও কনসোল অ্যাপ্লিকেশন হয় তবে কর্মীর থ্রেডটি সম্পূর্ণ হওয়ার আগে এটি বেরিয়ে আসা রোধ করতে কেবল একটি AutoResetEventএবং একটি নিক্ষেপ করুন WaitHandle:

Using System;
Using System.Threading;

class Foo
{
    static AutoResetEvent autoEvent = new AutoResetEvent(false);

    static void Main()
    {
        ThreadPoolQueueUserWorkItem(new WaitCallback(FireAway), autoEvent);
        autoEvent.WaitOne(); // Will wait for thread to complete
    }

    static void FireAway(object stateInfo)
    {
        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("5 seconds later");
        ((AutoResetEvent)stateInfo).Set();
    }
}

যদি এটি কোনও কনসোল অ্যাপ্লিকেশন না হয় এবং আমার সি # ক্লাসটি COM দৃশ্যমান হয় তবে আপনার অটোভেন্ট কাজ করবে? AutoEvent.WaitOne () ব্লক করছে?
ড্যান_ল

5
@ উদ্যান_এল - কোনও ধারণা নেই, কেন এটিকে নতুন প্রশ্ন হিসাবে জিজ্ঞাসা করবেন না এবং এইটির জন্য একটি রেফারেন্স দিন কেন?
কেভ

@ উদ্যান_, হ্যাঁ WaitOneসর্বদা অবরুদ্ধ এবং AutoResetEventসর্বদা কাজ করবে
এএএ

একক পটভূমির থ্রেড থাকলে কেবলমাত্র অটোসেটসেন্ট এখানে সত্যই কাজ করে। আমি ভাবছি যখন একাধিক থ্রেড ব্যবহার করা হয় তখন কোনও বাধা আরও ভাল। ডকস.মাইক্রোসফট.ওন
মার্টিন ব্রাউন

@ মার্টিনব্রাউন - নিশ্চিত না যে এটি সত্য। আপনার WaitHandleনিজস্ব AutoResetEventএকটি এবং এর সাথে একটি করে এর অ্যারে থাকতে পারে ThreadPool.QueueUserWorkItem। যে শুধু পর WaitHandle.WaitAll(arrayOfWaitHandles)
কেভ

15

একটি সহজ উপায় হ'ল প্যারামিটারলেস ল্যাম্বদা দিয়ে একটি থ্রেড তৈরি এবং শুরু করা:

(new Thread(() => { 
    FireAway(); 
    MessageBox.Show("FireAway Finished!"); 
}) { 
    Name = "Long Running Work Thread (FireAway Call)",
    Priority = ThreadPriority.BelowNormal 
}).Start();

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

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


দীর্ঘমেয়াদী বা অবরুদ্ধকরণের কারণে যখন আপনার ডেডিকেটেড থ্রেডের প্রয়োজন হয় তখন আপনার জন্য +1।
পল টার্নার

12

আপনি যখন Asp.Net এবং .Net 4.5.2 ব্যবহার করছেন তখন এটি করার প্রস্তাবিত উপায় QueueBackgroundWorkItem। এখানে একটি সহায়ক শ্রেণি রয়েছে:

public static class BackgroundTaskRunner
{     
    public static void FireAndForgetTask(Action action)
    {
        HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => // .Net 4.5.2 required
        {
            try
            {
                action();
            }
            catch (Exception e)
            {
                // TODO: handle exception
            }
        });
    }

    /// <summary>
    /// Using async
    /// </summary>
    public static void FireAndForgetTask(Func<Task> action)
    {
        HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => // .Net 4.5.2 required
        {
            try
            {
                await action();
            }
            catch (Exception e)
            {
                // TODO: handle exception
            }
        });
    }
}

ব্যবহারের উদাহরণ:

BackgroundTaskRunner.FireAndForgetTask(() =>
{
    FireAway();
});

বা অ্যাসিঙ্ক ব্যবহার:

BackgroundTaskRunner.FireAndForgetTask(async () =>
{
    await FireAway();
});

এটি আজুর ওয়েব সাইটগুলিতে দুর্দান্ত কাজ করে।

রেফারেন্স: নেট .৪.২.২ এএসপি.এনইটি অ্যাপ্লিকেশন থেকে পটভূমি জব শিডিউল করতে কুইউব্যাকগ্রাউন্ড ওয়ার্কআইটেম ব্যবহার করুন


7

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

Http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx- এ আরও পাওয়া যাবে


3
জিসি বলতে পারে যে জিনিসগুলি কখন তাদের কাছে কোনও রেফারেন্স না থাকলে তা পরিত্যাজ্য হয়। যদি এমন BeginInvokeএকটি মোড়ক বস্তু প্রদান করে যা একটি রেফারেন্স ধারণ করে, তবে এটির সাথে রেফারেন্স না দেওয়া হয় তবে যে অবজেক্টটি আসল ফলাফলের ডেটা ধারণ করে, তার সমস্ত রেফারেন্স পরিত্যাগ করার পরে মোড়ক বস্তু চূড়ান্তকরণের জন্য যোগ্য হয়ে উঠবে।
সুপারক্যাট

আমি প্রশ্ন করছি এটি "একটি ভাল পদ্ধতির নয়"; এটি সম্পর্কে পরীক্ষা করে নিন, আপনার যে ত্রুটি শর্ত সম্পর্কে উদ্বিগ্ন তা দিয়ে এবং দেখুন আপনার সমস্যা আছে কিনা। এমনকি আবর্জনা সংগ্রহ নিখুঁত না হলেও এটি সম্ভবত বেশিরভাগ অ্যাপ্লিকেশনগুলিকে লক্ষণীয়ভাবে প্রভাবিত করবে না। মাইক্রোসফ্ট অনুসারে, "যদি আপনি প্রয়োজনে ডেলিগেটের কাছ থেকে রিটার্নের মান পুনরুদ্ধার করতে এন্ডআইভোককে কল করতে পারেন তবে এটির প্রয়োজন হয় না the থেকে: এমএসডিএন.মাইক্রোসফটকম /en-us/library/0b1bf3y3(v=vs.90).aspx
অ্যাবাকাস


3

সবচেয়ে সহজ .NET 2.0 এবং পরবর্তী পদ্ধতিটি অ্যাসিঙ্কনোনাস প্রোগ্রামিং মডেলটি ব্যবহার করছে (উদাহরণস্বরূপ, একটি প্রতিনিধিটির দিকে আগমন)

static void Main(string[] args)
{
      new MethodInvoker(FireAway).BeginInvoke(null, null);

      Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId);

      Thread.Sleep(5000);
}

private static void FireAway()
{
    Thread.Sleep(2000);

    Console.WriteLine("FireAway: " + Thread.CurrentThread.ManagedThreadId );  
}

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