Her 15 saniyede bir çalışan bir unix betiği nasıl elde edilir?


84

İzlemek ve arka planda bir döngü (ve uyku) komut dosyası çalıştırmak da dahil olmak üzere birkaç çözüm gördüm, ancak hiçbir şey ideal olmadı.

Her 15 saniyede bir çalıştırılması gereken bir betiğim var ve cron saniyeleri desteklemediği için başka bir şey bulmaya başladım.

Unix'te her 15 saniyede bir komut dosyası çalıştırmanın en sağlam ve verimli yolu nedir? Komut dosyasının yeniden başlatıldıktan sonra da çalışması gerekir.


1
Koşmak ne kadar sürer?
Adam Matan

Yanıtlar:


77

Her dakika bir komut dosyası çalıştırmak için cron kullanırdım ve bu betiğin, çalıştırmalar arasında 15 saniyelik bir uyku ile betiğinizi dört kez çalıştırmasını sağlardım.

(Bu, komut dosyanızın hızlı çalıştığını varsayar - yoksa uyku zamanlarını ayarlayabilirsiniz.)

Bu şekilde, cron15 saniyelik çalışma sürenizin yanı sıra tüm avantajlarından da yararlanabilirsiniz .

Düzenleme: Ayrıca aşağıdaki @ bmb yorumuna bakın.


@Aiden: Ha! Düşmanım, tekrar karşılaşıyoruz!
RichieHindle

56
Komut dosyası çalıştırılması ne kadar sürdüğü konusunda tutarlı değilse, betiğin dört kopyasını alın. Başlamadan önce biri 15 saniye, diğeri 30, diğeri 45 ve diğeri sıfır uyur. Sonra dördünü de her dakika çalıştırın.
bmb

@RichieHindle - Korkma, dakikaları saniyelerle doldurmadığım için suikasta kurban gittim. Ama seni izliyorum: P
Aiden Bell

Bu cron nasıl her 1 dakikada bir tetiklenebilir
DevZer0

Aslında, outter-script iç betiği dört değil üç defa çalıştırmalıdır. Aksi takdirde, son dakikanın son koşusu, bir sonraki dakikanın ilk koşusu ile çakışacaktır. Bu, iç betiği dört yerine her dakika 5 kez çalıştırır.
Tulains Córdova

292

Komut dosyanızı cron'dan çalıştırmakta ısrar ediyorsanız:

* * * * * /foo/bar/your_script
* * * * * sleep 15; /foo/bar/your_script
* * * * * sleep 30; /foo/bar/your_script
* * * * * sleep 45; /foo/bar/your_script

ve / foo / bar / your_script için komut dosyası adınızı ve yolunu değiştirin


4
Bu benim için mükemmel çalıştı. Arka plan görevini kullanma konusundaki bunun üstündeki çözüm, birkaç alt işlem üretiyor ve benim tarafımda bellek sorunlarına neden oluyordu.
Hacknightly

3
php komut dosyası çalıştırılıyorsa şunu yapın:* * * * * sleep 15; php /foo/bar/your_script
ImaginedDesign

1
php script çalıştırarak eğer çizgiyi başa ekleyebilir #!/usr/bin/phpphp script üstüne ve çalıştırılabilir yapın
Aaron Blenkush

18
Bu çözüm için Google'da arama yapmak zorunda olduğum için utanıyorum. Belki yığılma akışı beni daha az düşündürüyor.
chris finne

@Hacknightly'ye yanıt olarak, yalnızca komut dosyaları 15 saniyelik çalışma süresini aştığında ve / veya görevler sistem tarafından kullanılabilecek yeterli belleği serbest bırakamadığında gerçekleşir
Abel Callejo

15

Yukarıdakilerin değiştirilmiş versiyonu:

mkdir /etc/cron.15sec
mkdir /etc/cron.minute
mkdir /etc/cron.5minute

/ etc / crontab dosyasına ekle:

* * * * * root run-parts /etc/cron.15sec > /dev/null 2> /dev/null
* * * * * root sleep 15; run-parts /etc/cron.15sec > /dev/null 2> /dev/null
* * * * * root sleep 30; run-parts /etc/cron.15sec > /dev/null 2> /dev/null
* * * * * root sleep 45; run-parts /etc/cron.15sec > /dev/null 2> /dev/null

* * * * * root run-parts /etc/cron.minute > /dev/null 2> /dev/null
*/5 * * * * root run-parts /etc/cron.5minute > /dev/null 2> /dev/null

13

Bunu arka planda çalıştırmayacak mısın?

#!/bin/sh
while [ 1 ]; do
    echo "Hell yeah!" &
    sleep 15
done

Bu, olabildiğince verimli. Önemli kısım yalnızca her 15 saniyede bir yürütülür ve komut dosyası geri kalan süre boyunca uyur (böylece döngüleri boşa harcamaz).


8
Düzenlemeler en az 8 karakter olmalıdır (ki bu aptalca, IMHO) bu yüzden &3. satırın sonuna ekleyemedim . Her durumda, olduğu gibi, bu her 15 saniyede bir çalışmıyor. Bu, her "15 saniyede + ne kadar uzun echo hellosürerse sürsün" çalışır. 0.01 saniye olabilir; 19 saat olabilir.
Parthian Shot


0

Nanosleep (2) kullanın . timespecNanosaniye hassasiyetiyle zaman aralıklarını belirtmek için kullanılan yapıyı kullanır .

struct timespec {
           time_t tv_sec;        /* seconds */
           long   tv_nsec;       /* nanoseconds */
       };

1
Devam edip nanosaniye hassasiyetine ihtiyaç duymadıklarını tahmin edeceğim, çünkü her 15 saniyede bir ürettikleri şey bir kabuk betiğidir, çekirdek iş parçacığı değil.
Parthian Shot

@ParthianShot belki ama asla bilemezsiniz.
Alexander Suraphel

0
#! /bin/sh

# Run all programs in a directory in parallel
# Usage: run-parallel directory delay
# Copyright 2013 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution

if [ $# -eq 0 ]
then
   echo
   echo "run-parallel by Marc Perkel"
   echo
   echo "This program is used to run all programs in a directory in parallel" 
   echo "or to rerun them every X seconds for one minute."
   echo "Think of this program as cron with seconds resolution."
   echo
   echo "Usage: run-parallel [directory] [delay]"
   echo
   echo "Examples:"
   echo "   run-parallel /etc/cron.20sec 20"
   echo "   run-parallel 20"
   echo "   # Runs all executable files in /etc/cron.20sec every 20 seconds or 3 times a minute."
   echo 
   echo "If delay parameter is missing it runs everything once and exits."
   echo "If only delay is passed then the directory /etc/cron.[delay]sec is assumed."
   echo
   echo 'if "cronsec" is passed then it runs all of these delays 2 3 4 5 6 10 12 15 20 30'
   echo "resulting in 30 20 15 12 10 6 5 4 3 2 executions per minute." 
   echo
   exit
fi

# If "cronsec" is passed as a parameter then run all the delays in parallel

if [ $1 = cronsec ]
then
   $0 2 &
   $0 3 &
   $0 4 &
   $0 5 &
   $0 6 &
   $0 10 &
   $0 12 &
   $0 15 &
   $0 20 &
   $0 30 &
   exit
fi

# Set the directory to first prameter and delay to second parameter

dir=$1
delay=$2

# If only parameter is 2,3,4,5,6,10,12,15,20,30 then automatically calculate 
# the standard directory name /etc/cron.[delay]sec

if [[ "$1" =~ ^(2|3|4|5|6|10|12|15|20|30)$ ]]
then
   dir="/etc/cron.$1sec"
   delay=$1
fi

# Exit if directory doesn't exist or has no files

if [ ! "$(ls -A $dir/)" ]
then
   exit
fi

# Sleep if both $delay and $counter are set

if [ ! -z $delay ] && [ ! -z $counter ]
then
   sleep $delay
fi

# Set counter to 0 if not set

if [ -z $counter ]
then
   counter=0
fi

# Run all the programs in the directory in parallel
# Use of timeout ensures that the processes are killed if they run too long

for program in $dir/* ; do
   if [ -x $program ] 
   then
      if [ "0$delay" -gt 1 ] 
      then
         timeout $delay $program &> /dev/null &
      else
         $program &> /dev/null &
      fi
   fi
done

# If delay not set then we're done

if [ -z $delay ]
then
   exit
fi

# Add delay to counter

counter=$(( $counter + $delay ))

# If minute is not up - call self recursively

if [ $counter -lt 60 ]
then
   . $0 $dir $delay &
fi

# Otherwise we're done

0

Önceki cevabımdan beri, farklı ve belki de daha iyi olan başka bir çözüm buldum. Bu kod, işlemlerin dakikada 60 defadan fazla mikrosaniye hassasiyetinde çalıştırılmasına izin verir. Bunun çalışması için usleep programına ihtiyacınız var. Saniyede 50 defaya kadar iyi olmalı.

#! /bin/sh

# Microsecond Cron
# Usage: cron-ms start
# Copyright 2014 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution

basedir=/etc/cron-ms

if [ $# -eq 0 ]
then
   echo
   echo "cron-ms by Marc Perkel"
   echo
   echo "This program is used to run all programs in a directory in parallel every X times per minute."
   echo "Think of this program as cron with microseconds resolution."
   echo
   echo "Usage: cron-ms start"
   echo
   echo "The scheduling is done by creating directories with the number of"
   echo "executions per minute as part of the directory name."
   echo
   echo "Examples:"
   echo "  /etc/cron-ms/7      # Executes everything in that directory  7 times a minute"
   echo "  /etc/cron-ms/30     # Executes everything in that directory 30 times a minute"
   echo "  /etc/cron-ms/600    # Executes everything in that directory 10 times a second"
   echo "  /etc/cron-ms/2400   # Executes everything in that directory 40 times a second"
   echo
   exit
fi

# If "start" is passed as a parameter then run all the loops in parallel
# The number of the directory is the number of executions per minute
# Since cron isn't accurate we need to start at top of next minute

if [ $1 = start ]
then
   for dir in $basedir/* ; do
      $0 ${dir##*/} 60000000 &
   done
   exit
fi

# Loops per minute and the next interval are passed on the command line with each loop

loops=$1
next_interval=$2

# Sleeps until a specific part of a minute with microsecond resolution. 60000000 is full minute

usleep $(( $next_interval - 10#$(date +%S%N) / 1000 ))

# Run all the programs in the directory in parallel

for program in $basedir/$loops/* ; do
   if [ -x $program ] 
   then
      $program &> /dev/null &
   fi
done

# Calculate next_interval

next_interval=$(($next_interval % 60000000 + (60000000 / $loops) ))

# If minute is not up - call self recursively

if [ $next_interval -lt $(( 60000000 / $loops * $loops)) ]
then
   . $0 $loops $next_interval &
fi

# Otherwise we're done

1
Tekrar göndermek yerine orijinali düzenleyin!
Vogon Jeltz

-1

Yürütmenin olası örtüşmesini önlemek için, o iş parçacığında açıklanan bir kilitleme mekanizması kullanın .


2
-1 OP, çakışan infazlardan kaçınması gerektiğini söylemedi; şey evresel olabilir. Artı, bu soruya cevap vermiyor.
Parthian Shot
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.