Komut saniyede ortalama 5 kez nasıl çalıştırılır?


21

API çağrısı yapan ve sonuçları içeren bir veritabanını güncelleyen bir komut satırı komut dosyası var.

API sağlayıcısıyla saniyede 5 API çağrısı sınırlaması var. Komutun yürütülmesi 0.2 saniyeden uzun sürüyor.

  • Eğer komutu sırayla çalıştırırsam, yeterince hızlı çalışmayacak ve saniyede sadece 1 veya 2 API çağrısı yapacağım.
  • Komutu ardışık olarak çalıştırırsam, ancak birkaç terminalden aynı anda çalıştırırsam, 5 çağrı / saniye sınırını aşabilirim.

Eğer iş parçacığı düzenlemenin bir yolu varsa, komut satırı betiğim saniyede neredeyse tam olarak 5 kez çalıştırılsın mı?

Örneğin, 5 veya 10 iş parçacığıyla çalışan ve önceki bir iş parçacığı 200ms'den daha önce çalıştırılmışsa, hiçbir iş parçacığı komut dosyasını yürütmez.


Tüm cevaplar, betiğinizin çağrıldığı sırada biteceği varsayımına bağlıdır. Arızalı bittiğinde kullanım durumunuz için kabul edilebilir mi?
Cody Gustafson

@CodyGustafson Düzensiz bitirmeleri tamamen kabul edilebilir. En azından kabul edilen cevapta böyle bir varsayım olduğuna inanmıyorum.
Benjamin,

Saniyedeki arama sayısını aştığınızda ne olur? API sağlayıcısı kısıtlarsa, sonunda herhangi bir mekanizmaya ihtiyacınız olmaz ... değil mi?
Floris,

@ Floris SDK'da bir istisna içinde tercüme edilecek bir hata mesajı döndürürler. Öncelikle, saniyede 50 kısma mesajı oluşturduğumda (böyle bir mesaja göre davranmanız gerekiyorsa) API sağlayıcısının mutlu olacağından şüpheliyim ve ikinci olarak API'yi aynı anda başka amaçlar için kullanıyorum. Aslında biraz daha yüksek olan limite ulaşmak istemiyorum.
Benjamin

Yanıtlar:


25

Bir GNU sisteminde ve eğer varsa pv, şunları yapabilirsiniz:

cmd='
   that command | to execute &&
     as shell code'

yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh

-P20En 20'de yürütmektir $cmdaynı anda.

-L10 hızı saniyede 10 bayt, yani saniyede 5 satır ile sınırlar.

Eğer $cmds'iniz yavaşlarsa ve 20 limitine ulaşılırsa, en az xargsbir $cmdörnek geri dönene kadar okumayı durduracaktır . pvboru doluncaya kadar aynı oranda borsaya yazmaya devam edecek (varsayılan 64KiB boruyla Linux'ta yaklaşık 2 saat sürecek).

Bu noktada, pvyazma durur. Ancak o zaman bile xargsokumaya devam ederken , pvgenel olarak saniyede ortalama 5 satır tutabilmek için mümkün olan en kısa sürede göndermesi gereken tüm satırları yakalamaya ve yakalamaya çalışacaktır.

Bunun anlamı, ortalama olarak ihtiyaç duyulan saniyede 5 çalıştırmayı karşılamak için 20 işlemle mümkün olduğu sürece, bunu yapmasıdır. Bununla birlikte, sınıra ulaşıldığında, yeni işlemlerin başlatılma hızı, pv'nin zamanlayıcısı tarafından değil, daha önceki cmd örneklerinin geri dönme hızına bağlı olacaktır. Örneğin, 20 şu anda çalışıyorsa ve 10 saniyedir çalışıyorsa ve 10 tanesi aynı anda bitirmeye karar verirse, bir kerede 10 yenisi başlayacaktır.

Örnek:

$ cmd='date +%T.%N; exec sleep 2'
$ yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
09:49:23.347013486
09:49:23.527446830
09:49:23.707591664
09:49:23.888182485
09:49:24.068257018
09:49:24.338570865
09:49:24.518963491
09:49:24.699206647
09:49:24.879722328
09:49:25.149988152
09:49:25.330095169

İki çalışma arasındaki gecikme her zaman tam olarak 0,2 saniye olmasa da ortalama olarak, saniyede 5 kez olacaktır.

İle ksh93(ya da zshsizin eğer sleepkomut fraksiyonel saniye destekler):

typeset -F SECONDS=0
n=0; while true; do
  your-command &
  sleep "$((++n * 0.2 - SECONDS))"
done

Bu eşzamanlı your-commands sayısına bağlı değildir .


Biraz test ettikten sonra, pvkomut tam olarak aradığım şey gibi görünüyor, daha iyisini umut edemezdim! Sadece bu satırda: yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" shSon shgereksiz değil mi?
Benjamin

1
Yani saniyede @Benjamin shiçindir $0sizin de $cmdkomut. Ayrıca kabuk tarafından hata mesajlarında kullanılır. Onsuz $0olacağını ydan yesaşağıdaki gibi hata mesajları olsun diye, y: cannot execute cmdAyrıca yapabilirdi ...yes sh | pv -qL15 | xargs -n1 -P20 sh -c "$cmd"
Stéphane Chazelas

Her şeyi anlaşılabilir parçalara ayırmak için mücadele ediyorum, TBH! Örnekte, bunu en son kaldırdınız sh; ve testlerimde çıkardığımda hiçbir fark göremiyorum!
Benjamin

@Benjamin. Kritik değil. Yalnızca $cmdkullanıyorsanız $0(neden?) Ve hata mesajlarında farklılaşacaktır . Örneğin cmd=/; ikinci shy: 1: y: /: Permission deniedsh: 1: sh: /: Permission denied
olmazsa

Çözümünüzle ilgili bir sorunum var: birkaç saat boyunca iyi çalışıyor, sonra bir noktada herhangi bir hata olmadan çıkıyor. Beklenmeyen yan etkileri olan borunun dolması ile ilgili olabilir mi?
Benjamin,

4

Basitçe, eğer emriniz 1 saniyeden az sürerse, her saniyede sadece 5 emri başlatabilirsiniz. Açıkçası, bu çok patlamış.

while sleep 1
do    for i in {1..5}
      do mycmd &
      done
done

Komutunuz 1 saniyeden uzun sürebilir ve komutları yaymak istiyorsanız, deneyebilirsiniz.

while :
do    for i in {0..4}
      do  sleep .$((i*2))
          mycmd &
      done
      sleep 1 &
      wait
done

Alternatif olarak, en az 1 saniye ile bağımsız olarak çalışan 5 ayrı döngüye sahip olabilirsiniz.

for i in {1..5}
do    while :
      do   sleep 1 &
           mycmd &
           wait
      done &
      sleep .2
done

Oldukça güzel bir çözüm. Basit ve saniyede tam 5 kez olması gerçeğini seviyorum, ancak aynı anda (her 200ms yerine) aynı anda 5 komutu başlatmak dezavantajı var ve belki de bir anda en fazla n iş parçacığı geçirme güvencesinden yoksundur. !
Benjamin

@Benjamin İkinci versiyonun döngüsüne 200ms'lik bir uyku ekledim. Bu ikinci sürümde sadece 5 başladığımız anda 5 cm'den daha fazla olamaz, sonra hepsini bekleriz.
meuh

Sorun şu ki, saniyede 5 saniyeden daha fazla zamana sahip olamazsınız; Tüm komut dosyalarının aniden yürütülmesi 1 saniyeden fazla sürerse, API sınırına ulaşmaktan çok uzaktasınız. Ayrıca, hepsini beklerseniz, tek bir engelleme komut dosyası diğerlerini engeller mi?
Benjamin,

@Benjamin Böylece, her biri minimum 1 saniyelik uykuya sahip 5 bağımsız döngü çalıştırabilirsiniz, 3. versiyona bakınız.
meuh

2

C programı ile

Örneğin, bir süre 0.2 saniye uyuyan bir iplik kullanabilirsiniz

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

pthread_t tid;

void* doSomeThing() {
    While(1){
         //execute my command
         sleep(0.2)
     } 
}

int main(void)
{
    int i = 0;
    int err;


    err = pthread_create(&(tid), NULL, &doSomeThing, NULL);
    if (err != 0)
        printf("\ncan't create thread :[%s]", strerror(err));
    else
        printf("\n Thread created successfully\n");



    return 0;
}

iş parçacığının nasıl oluşturulacağını bilmek için kullanın: bir iş parçacığı oluşturun (bu kodu yapıştırmak için kullandığım bağlantı budur)


Cevabınız için teşekkür ederim, her ne kadar ideal olarak C programlamayı içermeyen ama sadece mevcut Unix araçlarını kullanan bir şey arıyordum!
Benjamin

Evet, örneğin bu gücü karşısında stackoverflow cevabı birden çalışan iş parçacığı arasında paylaşılan bir belirteç kova kullanmak olabilir, ama Unix.SE üzerinde soran ziyade "programcı" yaklaşımı aranıyor :-) Yine de, daha bir "Güç kullanıcı" anlaşılacağı ccolduğunu Mevcut bir Unix aracı ve bu çok fazla kod değil!
Steve Jessop,

1

Node.js kullanarak , yanıtın geri arama işlevi ne kadar sürdüğü önemli değil, her 200 milisaniyede bir bash komut dosyasını çalıştıran tek bir iş parçacığı başlatabilirsiniz .

var util = require('util')
exec = require('child_process').exec

setInterval(function(){
        child  = exec('fullpath to bash script',
                function (error, stdout, stderr) {
                console.log('stdout: ' + stdout);
                console.log('stderr: ' + stderr);
                if (error !== null) {
                        console.log('exec error: ' + error);
                }
        });
},200);

Bu javascript her 200 milisaniyede bir çalışır ve yanıt geri çağırma işlevinden alınır function (error, stdout, stderr).

Bu şekilde, komutun yürütülmesinin ne kadar yavaş veya hızlı olduğundan veya bir yanıt için ne kadar beklemesi gerektiğinden bağımsız olarak saniyede 5 çağrıyı asla geçmeyeceğini kontrol edebilirsiniz.


Bu çözümü seviyorum: düzenli aralıklarla saniyede tam 5 komut başlatıyor . Görebildiğim tek dezavantajı, bir seferde en fazla n işlem yapmanın bir güvencesinden yoksun olmasıdır! Bu kolayca ekleyebileceğiniz bir şey mi? Node.js.'ye aşina değilim
Benjamin

0

Stéphane Chazelas'ın pvtemelli çözümünü bir süre kullandım, ancak bir süre sonra birkaç dakikadan birkaç saate kadar rastgele (ve sessizce) çıktığını öğrendim. - Düzenleme: Sebep, zaman zaman 255 durumundan çıkarak, azami yürütme süresinin aşılmasından dolayı PHP betiğimin zaman zaman ölmesiydi.

Böylece tam ihtiyacım olan şeyi yapan basit bir komut satırı aracı yazmaya karar verdim .

Orijinal hedefime ulaşmak, bu kadar basittir:

./parallel.phar 5 20 ./my-command-line-script

Halen 20 eşzamanlı işlem olmadıkça, saniyede neredeyse 5 komutu başlatır, bu durumda bir slot mevcut oluncaya kadar bir sonraki yürütmeyi atlar.

Bu araç bir durum 255 çıkışına duyarlı değildir.

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.