System.Threading.Timer সি # তে মনে হচ্ছে এটি কাজ করছে না। এটি প্রতি 3 সেকেন্ডে খুব দ্রুত চলে


112

আমি একটি টাইমার অবজেক্ট। আমি প্রতি মিনিটে এটি চালানো চাই। বিশেষত, এটি একটি OnCallBackপদ্ধতি চালানো উচিত এবং কোনও OnCallBackপদ্ধতি চলাকালীন নিষ্ক্রিয় হয়ে যায় । একবার কোনও OnCallBackপদ্ধতি শেষ হয়ে গেলে এটি (ক OnCallBack) একটি টাইমার পুনরায় চালু করে।

আমার এখনই যা আছে তা এখানে:

private static Timer timer;

private static void Main()
{
    timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds
    Console.ReadLine();
}

private static void OnCallBack()
{
    timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer
    Thread.Sleep(3000); //doing some long operation
    timer.Change(0, 1000 * 10);  //restarts the timer
}

তবে মনে হচ্ছে এটি কাজ করছে না। এটি প্রতি 3 সেকেন্ডে খুব দ্রুত চলে। এমনকি যদি কোনও সময়সীমা বাড়াতে হয় (1000 * 10)। দেখে মনে হচ্ছে যেন এটি অন্ধ দৃষ্টি দেয়1000 * 10

আমি কি ভুল করছি?


12
থেকে Timer.Change: "যদি ডেটটাইম শূন্য হয় (0), কলব্যাক পদ্ধতিটি অবিলম্বে ডাকা হবে" " দেখে মনে হচ্ছে এটি আমার কাছে শূন্য।
ড্যামিয়েন_ও_বিশ্বাসীরা

2
হ্যাঁ, তবে কি? একটি সময়কালও আছে।
অ্যালান করোমানো

10
সুতরাং যদি একটি সময়কাল আছে? উদ্ধৃত বাক্যটি পিরিয়ড মান সম্পর্কে কোনও দাবি করে না। এটি কেবল বলে "যদি এই মানটি শূন্য হয়, আমি তত্ক্ষণাত কলব্যাক শুরু করব"।
ড্যামিয়েন_এই অবিশ্বাসী

3
মজার বিষয় হল আপনি যদি সময় নির্ধারণের সময়সীমা এবং সময়কাল উভয়কে 0 তে সেট করেন তবে টাইমারটি প্রতি সেকেন্ডে চলবে এবং অবিলম্বে শুরু হবে।
কেলভিন

উত্তর:


230

এটি সিস্টেমের সঠিক ব্যবহার নয় h থ্রেডিং। টাইমার। আপনি যখন টাইমারটি ইনস্ট্যান্ট করেন, আপনার প্রায় সবসময় নিম্নলিখিতগুলি করা উচিত:

_timer = new Timer( Callback, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );

এটি যখন টাইমটি কেবলমাত্র বিরতিটি অতিক্রান্ত হয় তখন একবার টিক দেওয়ার নির্দেশ দেয়। তারপরে আপনার কলব্যাক ফাংশনে আপনি টাইমার পরিবর্তন করুন একবার কাজ শেষ হয়ে গেলে, আগে নয়। উদাহরণ:

private void Callback( Object state )
{
    // Long running operation
   _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );
}

সুতরাং লকিং মেকানিজমের কোনও প্রয়োজন নেই কারণ কোনও সাদৃশ্য নেই। টাইমার পরবর্তী ব্যবধানটি পরবর্তী ব্যবধানটি কেটে যাওয়ার পরে + দীর্ঘ চলমান ক্রিয়াকলাপের সময়টি ফায়ার করবে।

আপনার যদি টাইমারটি ঠিক এন মিলিসেকেন্ডে চালানোর দরকার হয় তবে আমি পরামর্শ দিচ্ছি যে আপনি স্টপওয়াচ ব্যবহার করে দীর্ঘ চলমান অপারেশনের সময়টি পরিমাপ করুন এবং তারপরে যথাযথ পরিবর্তন পদ্ধতিটি কল করুন:

private void Callback( Object state )
{
   Stopwatch watch = new Stopwatch();

   watch.Start();
   // Long running operation

   _timer.Change( Math.Max( 0, TIME_INTERVAL_IN_MILLISECONDS - watch.ElapsedMilliseconds ), Timeout.Infinite );
}

আমি নেট করার জন্য দৃ strongly়ভাবে উত্সাহিত করি এবং সিএলআর ব্যবহার করছি যারা জেফ্রি রিখটারের বইটি সিএল-এর মাধ্যমে সিএলআর দিয়ে পড়েনি, যত তাড়াতাড়ি সম্ভব পড়ার জন্য। টাইমার এবং থ্রেড পুলগুলি সেখানে দুর্দান্ত বিবরণে ব্যাখ্যা করা হয়েছে।


6
আমি যে তার সাথে একমত না private void Callback( Object state ) { // Long running operation _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite ); }Callbackকোনও অপারেশন শেষ হওয়ার আগে আবার ডাকা যেতে পারে।
অ্যালান করোমানো

2
আমি যা বোঝাতে চেয়েছি তা Long running operationহতে পারে তখন আরও অনেক বেশি সময় লাগত TIME_INTERVAL_IN_MILLISECONDS। তাহলে কি হবে?
অ্যালান করোমানো

31
কলব্যাক আবার কল করা হবে না, এটি পয়েন্ট। এই কারণেই আমরা টাইমআউটটি পাস করি second দ্বিতীয় পরামিতি হিসাবে অনির্দিষ্ট। এর মূল অর্থ টাইমারটির জন্য আবার টিক চিহ্ন দেবেন না। তারপরে আমরা ক্রিয়াকলাপটি শেষ করার পরে পুনরায় নির্ধারণ করুন।
ইভান জ্লাতানোভ

নবজাতক এখানে থ্রেডিংয়ের জন্য - আপনি কি ThreadPoolটাইমার দিয়ে পাস করে এমনটি করা সম্ভব বলে মনে করেন? আমি এমন একটি দৃশ্যের কথা ভাবছি যেখানে একটি নির্দিষ্ট বিরতিতে কোনও কাজ করার জন্য নতুন থ্রেড তৈরি করা হয়েছে - এবং তারপরে সম্পূর্ণ হওয়ার পরে থ্রেড পুলে ছেড়ে দেওয়া হবে।
jedd.ahyoung

2
System.Threading.Timer একটি থ্রেড পুল টাইমার, এটি থ্রেড পুলে এটি কলব্যাকগুলি সম্পাদন করে, কোনও উত্সর্গীকৃত থ্রেড নয়। টাইমার কলব্যাক রুটিন সম্পূর্ণ করার পরে, কলব্যাক কার্যকর করা থ্রেডটি পুলটিতে ফিরে যায়।
ইভান জ্লাতানোভ

14

টাইমার থামানোর প্রয়োজন নেই, এই পোস্ট থেকে দুর্দান্ত সমাধান দেখুন :

"আপনি টাইমারকে কলব্যাক পদ্ধতিতে গুলি চালিয়ে যেতে দিতে পারলেন কিন্তু আপনার অ-পুনঃপ্রবিধান কোডটি একটি মনিটরে মুড়ে রাখতে পারেন ry

private void CreatorLoop(object state) 
 {
   if (Monitor.TryEnter(lockObject))
   {
     try
     {
       // Work here
     }
     finally
     {
       Monitor.Exit(lockObject);
     }
   }
 }

এটা আমার ক্ষেত্রে নয় আমার ঠিক টাইমার থামানো দরকার।
অ্যালান করোমানো

আপনি কি আবার একবারে কলব্যাক প্রবেশ করা আটকাতে চাইছেন? না হলে আপনি কী অর্জন করার চেষ্টা করছেন?
ইভান লিওনেনকো

1. একাধিকবার কলব্যাক প্রবেশ করা আটকাবেন। 2. খুব বেশি সময় নির্বাহ করা আটকাবেন।
অ্যালান করোমানো

এটি ঠিক কি করে। # 2 যতক্ষণ না অবজেক্ট লক করা থাকে যদি স্টেটমেন্টের ঠিক পরে ফিরে আসে ততক্ষণ ওভারহেড হয় না, বিশেষত আপনার যদি এত বড় ব্যবধান থাকে।
ইভান লিওনেনকো

1
এটি গ্যারান্টি দেয় না যে কোডটি শেষ কার্যকর হওয়ার পরে <অন্তঃকালীন> এর চেয়ে কম বলা হয় (টাইমারটির একটি নতুন টিকটি কোনও পূর্ববর্তী টিকটি লকটি প্রকাশের পরে মাইক্রোসেকেন্ডে বহিস্কার করা যেতে পারে)। এটি নির্ভর করে যদি এটি কঠোর প্রয়োজন হয় বা না (সমস্যার বিবরণ থেকে সম্পূর্ণ পরিষ্কার নয়)।
মার্কো এমপি

9

ব্যবহার করছে System.Threading.Timerবাধ্যতামূলক ?

যদি না হয়, System.Timers.Timerকুশলী হয়েছে Start()এবং Stop()পদ্ধতি (এবং AutoResetসম্পত্তি আপনি যে মিথ্যাতে সেট করতে পারেন, তাই Stop()প্রয়োজন হয় না এবং আপনি কেবল কল Start()নির্বাহ পর)।


3
হ্যাঁ, তবে এটি সত্যিকারের প্রয়োজন হতে পারে, বা এটি ঘটেছে যে টাইমারটি বেছে নেওয়া হয়েছিল কারণ এটি সর্বাধিক ব্যবহৃত। দুঃখজনকভাবে .NET এর সাথে প্রচুর পরিমাণে টাইমার অবজেক্ট রয়েছে, 90% এর জন্য ওভারল্যাপিং রয়েছে তবে এখনও (কখনও কখনও সাবলেটভাবে) আলাদা। অবশ্যই এটি যদি প্রয়োজন হয় তবে এই সমাধানটি মোটেই প্রযোজ্য নয়।
মার্কো এমপি

2
অনুযায়ী ডকুমেন্টেশন : Systems.Timer বর্গ শুধুমাত্র .NET ফ্রেমওয়ার্ক পাওয়া যায়। এটি .NET স্ট্যান্ডার্ড লাইব্রেরিতে অন্তর্ভুক্ত নেই এবং অন্যান্য প্ল্যাটফর্মগুলিতে যেমন NET কোর বা ইউনিভার্সাল উইন্ডোজ প্ল্যাটফর্মে উপলব্ধ নেই। এই প্ল্যাটফর্মগুলিতে পাশাপাশি সমস্ত .NET প্ল্যাটফর্মের বহনযোগ্যতার জন্য আপনার পরিবর্তে System.Threading.Timer ক্লাস ব্যবহার করা উচিত।
নোটগেইন বলেছেন

3

আমি শুধু করতাম:

private static Timer timer;
 private static void Main()
 {
   timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds
   Console.ReadLine();
 }

  private static void OnCallBack()
  {
    timer.Dispose();
    Thread.Sleep(3000); //doing some long operation
    timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds
  }

এবং পিরিয়ড প্যারামিটারটিকে উপেক্ষা করুন, যেহেতু আপনি নিজেই সাময়িকীটি নিয়ন্ত্রণ করার চেষ্টা করছেন।


আপনার মূল কোডটি যত তাড়াতাড়ি চলমান, যেহেতু আপনি প্যারামিটারের 0জন্য নির্দিষ্ট করে dueTimeচলেছেন। থেকে Timer.Change:

যদি ডাইটাইম শূন্য হয় (0), কলব্যাক পদ্ধতিটি অবিলম্বে ডাকা হবে।


2
এটি কি টাইমার নিষ্পত্তি করা প্রয়োজন? কেন আপনি Change()পদ্ধতি ব্যবহার করবেন না ?
অ্যালান করোমানো

21
প্রতিবার টাইমার নিষ্পত্তি করা একেবারে অপ্রয়োজনীয় এবং ভুল।
ইভান জ্লাতানোভ

0
 var span = TimeSpan.FromMinutes(2);
 var t = Task.Factory.StartNew(async delegate / () =>
   {
        this.SomeAsync();
        await Task.Delay(span, source.Token);
  }, source.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

source.Cancel(true/or not);

// or use ThreadPool(whit defaul options thread) like this
Task.Start(()=>{...}), source.Token)

আপনি যদি ভিতরে কিছু লুপ থ্রেড ব্যবহার করতে চান ...

public async void RunForestRun(CancellationToken token)
{
  var t = await Task.Factory.StartNew(async delegate
   {
       while (true)
       {
           await Task.Delay(TimeSpan.FromSeconds(1), token)
                 .ContinueWith(task => { Console.WriteLine("End delay"); });
           this.PrintConsole(1);
        }
    }, token) // drop thread options to default values;
}

// And somewhere there
source.Cancel();
//or
token.ThrowIfCancellationRequested(); // try/ catch block requred.
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.