Saniyeler içinde uyumak için bir döngüye ihtiyacınız var


14

Makinemde, saniye kesirleri olarak ifade edilen bir gecikmeye sahip olması gereken 1 basit komutu yineleyen bir döngü yürütmem gerekiyor.

Diyelim ki ihtiyacım var:

  • artan bir numaralandırma (dosya-0, dosya-1, dosya-2, ...) içeren bir dosyayı bu örnek için önemsiz bir şeyle oluşturmak time > file-$x
  • Bunu her saniyenin 1 / 70'inde yapmalıyım (örnek olarak) çünkü zamanımı saniyenin kesirleriyle ifade etmek istiyorum.

Gerçekten nasıl hassas olabilirim ve her şeyin bir bash betiği ile ifade edilmesini sağlayabilir miyim?

Kesir belirlenemeyen bir miktar üretebilir, kesin olmalıyım ve bu yüzden en az 4-5 ondalık sayıya ihtiyacım var.

Yanıtlar:


12

Kesirden bash'ta ondalıklara dönüştürmek için,

myvar=$(echo "scale=4; 5/10" | bc)

Ardından, bu değer üzerinde bir döngü yapmak için,

for i in $(seq 1 1000); do sleep $myvar; done

Debian (GNU) üzerindeki uyku uygulamam ondalık uyku değerlerini kabul ediyor gibi görünüyor.

Ne yazık ki..

Bu tür bir hassasiyetle (4-5 ondalık basamak), perl betiği veya derlenmiş bir program gibi bir şey isteyeceksiniz; döngü içindeki herhangi bir programı çağırmak yükü bir sürü titreşim ekleyecektir. Uykunun kendisi birkaç milisaniye sürecektir.

Aşağıdakileri düşünün, 1000 kez yapılan ikinci bir uykunun 1 / 10.000'i:

time for i in $(seq 1 1000); do sleep 0.0001; done

real    0m2.099s
user    0m3.080s
sys     0m1.464s

Beklenen sonuç saniyenin 1 / 10'u olacaktır. Uyku, istediğiniz toleransa yakın bir yerde değildir.

/programming/896904/how-do-i-sleep-for-a-millisecond-in-perl

perl's Time kullanarak :: HiRes, 1000 * 1000 mikrosaniye:

my $i=0;
for($i=0;$i<=1000;$i++) {
        usleep(1000);
}

real    0m1.133s
user    0m0.024s
sys     0m0.012s

bizi bir saniyeye çok yaklaştırıyor.


4-5 ondalık sayı elde etmek mümkün değilse, alternatif olarak mümkün olan en iyi sonucu alırım, ama benim açımdan bunu ondalık veya saniye değil kesirler halinde ifade etmem gerekiyor.
user1717079

Bir kesirin bash dahil herhangi bir kodlama dilinde ondalık sayıya dönüştürülmesi tamamen önemsizdir. örneğin yankı "ölçek = 4; 5/10" | bc
Rob Bos

şimdi ifade dönüştürmek için nasıl var, sorun şimdi basit bir bash gerçekten yavaş ve sadece bu frekansı takip edemez ...
user1717079

Evet, saniyenin 1 / 10'undan daha kesin bir şey istiyorsanız, programın döngü içinde ek yükü çağırmasını önlemek için muhtemelen perl veya python isteyeceksiniz.
Rob Bos

7

Belki sadece koşabilirsin

sleep 0.7

?

man 1 sleep

Benim üzerinde archlinuxdistro:

AÇIKLAMA NUMBER saniye duraklayın. SUFFIX saniyeler için 's' (varsayılan), dakikalar için 'm', saatler için 'h' veya günler için 'd' olabilir. NUMBER bir tamsayı gerektiren uygulamaların çoğundan farklı olarak, burada NUMBER isteğe bağlı bir kayan nokta sayısı olabilir. İki veya daha fazla bağımsız değişken verildiğinde, değerlerinin toplamıyla belirtilen süre kadar duraklayın.


sleepkesirlere izin verir? sahte bir döngü ile tam bir örnek sunabilir misiniz?
user1717079

0.7 Sorunumu ifade eden bir kesir değil ... benim sorunum ayrıntı ile ilgili; 1/3 hakkında düşünün ve uyku ile kesin olmaya çalışın.
user1717079

6

Bir süreç oluşturmak ve içine yeni bir yürütülebilir dosya yüklemek birkaç milisaniye sürer, bu nedenle bu tür bir hassasiyet gerçekten mantıklı değildir. Ayrıca, birçok sistemdeki CPU süresinin 10 ms'ye kadar dilimlerle ayrıldığını unutmayın.

Bununla birlikte, bazı sleepuygulamalar kesirli sayıda saniye alır ve hem zsh hem de ksh93 $SECONDSözel değişkenlerini kesirli hale getirebilir typeset -F SECONDS.

Örnek (zsh):

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((1./70)); date +%s.%N; done | { head -n3;echo ..;tail -n3; }; echo $SECONDS
1350076317.374870501
1350076317.391034397
1350076317.407278461
..
1350076318.464585550
1350076318.480887660
1350076318.497133050
1.1393780000

Üzgünüz, sürüklendi. Uyku süresini aşağıdakilere göre ayarlayabilirsiniz $SECONDS:

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((i/70. - SECONDS)); date +%s.%N; done | { head -n3;echo ...;tail -n3; }; echo $SECONDS
1350076420.262775654
1350076420.277012997
1350076420.291302750
../..
1350076421.219682227
1350076421.234134663
1350076421.248255685
1.0020580000

Bu 2 ekstra milisaniye muhtemelen sonuncuyu sleepve datekomutları çalıştırırken hesaba katılmalıdır .

Ayrıca zsh'ın zselectsaniyenin yüzde biri cinsinden zaman aşımına sahip bir yerleşimi olduğunu unutmayın . Ve ksh93 sleepyerleşik (ve kayan noktaları kabul eder) ve printftarih / saatleri yazdırabilir.

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do ((i<4 || i>67)) && printf '%(%S.%N)T\n' now; sleep $((i/70.-SECONDS)); done; echo $SECONDS
20.823349000
20.837510000
20.851663000
21.780099000
21.794254000
21.808405000
0.9992358685

Eğer daha hassas bir şey istiyorsanız, muhtemelen gerçek zamanlı yetenekleri ile gerçek zamanlı işletim sistemi veya işletim sistemi isteyeceksiniz ve kesinlikle değil bir kabuk kullanın.


sleep 1/70makinemde izin verilmiyor ...
user1717079

ulaşmak istediğim şeye yakın bile değilim, işleri daha hızlı nasıl yürütebilirim?
user1717079

Üzgünüm, kesirli olarak, n ve m'nin tamsayı olduğu n / m olarak değil, kesirli kısmı olan ondalık sayılar olarak ifade ettim. Uygun İngilizce terminolojisi hakkında emin olmadığım halde onlara ondalık kayan nokta sayıları da diyebilirsiniz
Stéphane Chazelas 12:12

Ben kabuk kaçınacağını düşünüyorum ...
user1717079

Cevap doğru. Kabuklar ve süreçler genellikle milisaniye çözünürlük için uygun değildir. Güvenilir performans için, bizi uykuya (3) veya benzerine çağıran bir program derlemeniz gerekir; ayrıca çekirdeğinizi farklı bir yapılandırmayla yeniden derlemeniz gerekebilir; veya en azından çekirdeğinizin çalışma zamanı zamanlayıcısına farklı parametreler besleyin. Bunu yapmak önemsiz değil. Standart çekirdekli standart bir Debian kurulumunun sınırlı gerçek zamanlı özellikleri vardır. Yine de, nice (1) komutunu kontrol etmek isteyebilirsiniz; o yardımcı olabilir.
thb

3

Kabuğunuz sleepkesir kabul etmezse perl kullanın.

sleep_fraction() {
  /usr/bin/perl -e "select(undef, undef, undef, $1)"
}

sleep_fraction 0.01428

Kesriyi bulmanız gerekiyorsa, echo "scale=5; 1/70" | bc


0

Alpine Linux (Busybox) altında mikrosaniye döngü yapabilirsiniz (bir saniyeye usleep 10eşdeğer 0.00001)

GNU sleep saniyenin kesirlerini destekler: sleep 0.00001

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.