প্রতি সেকেন্ডে ঠিক একবার লুপ চালানো


33

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

এমন লুপ লেখার কি কোনও উপায় আছে যা আমি প্রতি সেকেন্ডে একটি প্রিন্টআউট পাওয়ার গ্যারান্টিযুক্ত? (অবশ্যই, প্রদত্ত যে লুপের গণনাগুলি এক সেকেন্ডের চেয়ে কম সময় নেয় :))

while true; do
  TIME=$(date +%H:%M:%S)
  # some calculations which take a few hundred milliseconds
  FOO=...
  BAR=...
  printf '%s  %s  %s\n' $TIME $FOO $BAR
  sleep 1
done

সম্ভবত সহায়ক: unix.stackexchange.com/q/60767/117549
জেফ

26
মনে রাখবেন যে " প্রতি সেকেন্ডে অবিকল একবারে" বেশিরভাগ ক্ষেত্রেই আক্ষরিকভাবে সম্ভব হয় না কারণ আপনি (সাধারণত) একটি প্রিমিটিভলি মাল্টিটাস্কিং কার্নেলের উপরের ইউজারস্পেসে চলছেন যা আপনার কোডটি যথাযথ দেখায় তা নির্ধারিত করবে (যাতে আপনি ঘুমের পরে অবিলম্বে নিয়ন্ত্রণ ফিরে পেতে না পারেন) শেষ হয়, উদাহরণস্বরূপ)। আপনি যদি সি কোডটি না লিখে থাকেন যা sched(7)এপিআইতে কল করে (POSIX: দেখুন <sched.h>এবং সেখান থেকে লিঙ্কিত পৃষ্ঠাগুলি), আপনার মূলত এই ফর্মটির রিয়েল-টাইম গ্যারান্টি থাকতে পারে না।
কেভিন

@ কেভিন কী বলেছিলেন, তার ব্যাক আপ করার জন্য, ঘুম () ব্যবহার করে কোনও ধরণের সঠিক সময় ব্যর্থ হওয়ার চেষ্টা করা ব্যর্থ হয়েছে, এটি কেবল সর্বনিম্ন 1 সেকেন্ড ঘুমের গ্যারান্টি দেয়। যদি আপনার সত্যিকারের সঠিক সময়টির দরকার হয় তবে আপনাকে সিস্টেমের ঘড়ির দিকে নজর দিতে হবে (CLOCK_MONOTONIC দেখুন) এবং শেষ-ইভেন্ট -1 -র উপর ভিত্তি করে জিনিসগুলি ট্রিগার করতে হবে এবং নিশ্চিত করুন যে আপনি> 1 সেকেন্ড চালানোর জন্য যাত্রা করছেন না, পরের বার গণক পর কিছু অপারেশন ইত্যাদি
জন ইউ


ঠিক একবারে সেকেন্ডে = একটি ভিসিএক্সও ব্যবহার করুন। কেবলমাত্র একটি সফ্টওয়্যার সমাধান আপনাকে "যথেষ্ট ভাল" পেতে পারে তবে সুনির্দিষ্ট নয়।
ইয়ান ম্যাকডোনাল্ড

উত্তর:


65

মূল কোডটির সাথে কিছুটা কাছাকাছি থাকতে আমি যা করি তা হ'ল:

while true; do
  sleep 1 &
  ...your stuff here...
  wait # for sleep
done

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

সুতরাং আপনার স্টাফ কখনও সমান্তরালে চলে না, এবং পটভূমিতে নয়, সুতরাং ভেরিয়েবলগুলিও প্রত্যাশার মতো কাজ করে।

মনে রাখবেন যে আপনি যদি অতিরিক্ত ব্যাকগ্রাউন্ডের কাজগুলিও শুরু করেন তবে আপনাকে বিশেষভাবে প্রক্রিয়াটির waitজন্য অপেক্ষা করতে নির্দেশ পরিবর্তন করতে হবে sleep

আপনার যদি এটি আরও নির্ভুল হওয়ার প্রয়োজন হয় তবে আপনাকে সম্ভবত এটি পুরো সেকেন্ডের পরিবর্তে সিস্টেম ঘড়ির সাথে স্লাইড এমএস করতে হবে।


সিস্টেম ঘড়ির সাথে কীভাবে সিঙ্ক করবেন? আসলেই ধারণা নেই, বোকা চেষ্টা:

ডিফল্ট:

while sleep 1
do
    date +%N
done

আউটপুট: 003511461 010510925 016081282 021643477 028504349 03 ... (বাড়তে থাকে)

সিঙ্ক করা:

 while sleep 0.$((1999999999 - 1$(date +%N)))
 do
     date +%N
 done

আউটপুট: 002648691 001098397 002514348 001293023 001679137 00 ... (একই থাকে)


9
এই ঘুম / ওয়েট ট্রিক সত্যিই চালাক!
ফিলিফআর

আমি ভাবছি sleepভগ্নাংশ সেকেন্ডের সমস্ত বাস্তবায়ন যদি হ্যান্ডেল হয়?
jcaron

1
@ jcaron তাদের সবকটিই নয়। তবে এটি gnu ঘুম এবং ব্যস্তবক্স ঘুমের জন্য কাজ করে তাই এটি বিদেশী নয়। আপনি সম্ভবত একটি সাধারণ ফ্যালব্যাক করতে পারেন sleep 0.9 || sleep 1যেমন অবৈধ প্যারামিটারটি ঘুমকে ব্যর্থ করার একমাত্র কারণ।
frostschutz

@ ফ্রস্টসচুটজ আমি আশা করি নির্বিকার বাস্তবায়ন দ্বারা sleep 0.9ব্যাখ্যা করা হবে sleep 0(যা যা atoiহবে তা প্রদত্ত )। নিশ্চিত না যে এর ফলে আসলে কোনও ত্রুটি ঘটবে।
jcaron

1
আমি এই প্রশ্নটি অনেক আগ্রহ ছড়িয়ে দেখে খুশি। আপনার পরামর্শ এবং উত্তর খুব ভাল। এটি কেবল দ্বিতীয়টির মধ্যেই রাখে না, এটি যতটা সম্ভব পুরো দ্বিতীয়টির সাথেও আঁকড়ে থাকে। চিত্তাকর্ষক! (! দ্রষ্টব্য একটি পার্শ্ব নোট অন, এক গনুহ Coreutils এবং ব্যবহার ইনস্টল করতে হবে gdateMacOS উপর করতে date +%Nহবে।)
forthrin

30

আপনি যদি নিজের লুপটিকে কোনও স্ক্রিপ্ট / অনেলিনারে পুনর্গঠন করতে পারেন তবে এটি করার সহজ উপায়টি watchএর preciseবিকল্প এবং এর বিকল্পটি।

আপনি এর সাথে এফেক্টটি দেখতে পাবেন watch -n 1 sleep 0.5- এটি কয়েক সেকেন্ড গণনা দেখিয়ে দেবে, তবে মাঝে মাঝে একটি সেকেন্ডে এড়িয়ে যাবে। এটি হিসাবে চালানো watch -n 1 -p sleep 0.5প্রতি সেকেন্ডে, প্রতি সেকেন্ডে দুবার আউটপুট আসবে এবং আপনি কোনও এড়িয়ে যাবেন না।


11

পটভূমির কাজ হিসাবে চালিত সাব-শেলের মধ্যে ক্রিয়াকলাপগুলি চালানো তাদেরকে এতটা হস্তক্ষেপ না করে তোলে sleep

while true; do
  (
    TIME=$(date +%T)
    # some calculations which take a few hundred milliseconds
    FOO=...
    BAR=...
    printf '%s  %s  %s\n' "$TIME" "$FOO" "$BAR"
  ) &
  sleep 1
done

এক সেকেন্ড থেকে কেবলমাত্র "চুরি" হওয়া সময়টি সাবশেলটি চালু করার সময় হতে পারে, সুতরাং এটি শেষ পর্যন্ত দ্বিতীয়টি এড়িয়ে যায়, তবে আশা করি মূল কোডের চেয়ে কম বার।

ব্যবহার আপ subshell প্রান্ত কোড যদি আরো একটি দ্বিতীয় চেয়ে, লুপ জমা পটভূমি কাজ শুরু হবে এবং শেষ পর্যন্ত সম্পদ ফুরিয়ে।


9

আরেকটি বিকল্প (যদি আপনি ব্যবহার করতে না পারেন, উদাহরণস্বরূপ, watch -pমেলস্ট্রোমের পরামর্শ অনুসারে) হ'ল sleepenh[ ম্যানপেজ ], যা এটির জন্য ডিজাইন করা হয়েছে।

উদাহরণ:

#!/bin/sh

t=$(sleepenh 0)
while true; do
        date +'sec=%s ns=%N'
        sleep 0.2
        t=$(sleepenh $t 1)
done

উল্লেখ্য sleep 0.2সেখানে অনুকরণ কিছু সময় সাপেক্ষ টাস্ক 200ms প্রায় খাওয়া করছেন। তবুও, ন্যানোসেকেন্ডস আউটপুট স্থিতিশীল থাকে (ভাল, অ-রিয়েলটাইম ওএস মান দ্বারা) - প্রতি সেকেন্ডে একবার এটি ঘটে:

sec=1533663406 ns=840039402
sec=1533663407 ns=840105387
sec=1533663408 ns=840380678
sec=1533663409 ns=840175397
sec=1533663410 ns=840132883
sec=1533663411 ns=840263150
sec=1533663412 ns=840246082
sec=1533663413 ns=840259567
sec=1533663414 ns=840066687

এটি 1 মিমি থেকে কম এবং কোনও প্রবণতা নেই। এটা বেশ ভাল; সিস্টেমে কোনও লোড থাকলে আপনার কমপক্ষে 10 মিমি বাউন্স আশা করা উচিত - তবে সময়ের সাথে এখনও কোনও প্রবাহ ছাড়েনি। অর্থাৎ আপনি এক সেকেন্ডও হারাবেন না।


7

সাথে zsh:

n=0
typeset -F SECONDS=0
while true; do
  date '+%FT%T.%2N%z'
  ((++n > SECONDS)) && sleep $((n - SECONDS))
done

যদি আপনার ঘুম ভাসমান পয়েন্ট সেকেন্ডে সমর্থন না করে তবে আপনি zshএর zselectপরিবর্তে (এ পরে zmodload zsh/zselect) ব্যবহার করতে পারেন :

zmodload zsh/zselect
n=0
typeset -F SECONDS=0
while true; do
  date '+%FZ%T.%2N%z'
  ((++n > SECONDS)) && zselect -t $((((n - SECONDS) * 100) | 0))
done

লুপের কমান্ডগুলি চালিত হতে এক সেকেন্ডেরও কম সময় লাগবে না dri


0

আমার পসিক্স শেল স্ক্রিপ্টের জন্য ঠিক একই প্রয়োজনীয়তা ছিল, যেখানে সমস্ত সহায়ক (ইউএসপ, জিএনইউস্লিপ, স্লিপেন, ...) উপলব্ধ নেই।

দেখুন: https://stackoverflow.com/a/54494216

#!/bin/sh

get_up()
{
        read -r UP REST </proc/uptime
        export UP=${UP%.*}${UP#*.}
}

wait_till_1sec_is_full()
{
    while true; do
        get_up
        test $((UP-START)) -ge 100 && break
    done
}

while true; do
    get_up; START=$UP

    your_code

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