प्रति सेकंड औसतन 5 बार कमांड कैसे चलाएं?


21

मेरे पास एक कमांड-लाइन स्क्रिप्ट है जो एपीआई कॉल करती है और परिणामों के साथ एक डेटाबेस को अपडेट करती है।

मेरे पास एपीआई प्रदाता के साथ प्रति सेकंड 5 एपीआई कॉल की सीमा है। स्क्रिप्ट को निष्पादित करने में 0.2 सेकंड से अधिक समय लगता है।

  • यदि मैं कमांड को क्रमिक रूप से चलाता हूं, तो यह तेजी से नहीं चलेगा और मैं केवल 1 या 2 एपीआई कॉल प्रति सेकंड कर रहा हूं।
  • यदि मैं क्रमिक रूप से चलाती हूं, लेकिन एक साथ कई टर्मिनलों से, मैं 5 कॉल / दूसरी सीमा से अधिक हो सकती हूं।

अगर थ्रेड को ऑर्केस्ट्रेट करने का कोई तरीका है, तो मेरी कमांड-लाइन स्क्रिप्ट को लगभग 5 बार प्रति सेकंड निष्पादित किया जाता है?

उदाहरण के लिए कुछ ऐसा है जो 5 या 10 थ्रेड्स के साथ चलेगा, और कोई थ्रेड स्क्रिप्ट निष्पादित नहीं करेगा यदि पिछले थ्रेड ने 200ms से कम समय पहले निष्पादित किया हो।


सभी उत्तर इस धारणा पर निर्भर करते हैं कि आपकी स्क्रिप्ट उसी क्रम में समाप्त हो जाएगी जिसे इसे कहा जाता है। क्या यह आपके उपयोग के मामले के लिए स्वीकार्य है यदि वे ऑर्डर से बाहर हैं?
कोडी गुस्ताफसन

@CodyGustafson यह पूरी तरह से स्वीकार्य है अगर वे आदेश से बाहर निकलते हैं। मुझे नहीं लगता कि स्वीकृत जवाब में ऐसी कोई धारणा है, कम से कम?
बेंजामिन

यदि आप प्रति सेकंड कॉल की संख्या से अधिक हो गए तो क्या होगा? अगर एपीआई प्रदाता थ्रॉटल करता है, तो आपको अपने अंत में किसी भी तंत्र की आवश्यकता नहीं है ... क्या आप?
फ्लोरिस

@ फ़्लोरिस वे एक त्रुटि संदेश लौटाएंगे जो एसडीके में एक अपवाद के रूप में अनुवाद करेगा। सबसे पहले मुझे संदेह है कि अगर मैं प्रति सेकंड 50 थ्रॉटल संदेश उत्पन्न करता हूं, तो आप एपीआई प्रदाता खुश होंगे (आप इस तरह के संदेशों के अनुसार कार्य करने वाले हैं), और दूसरी बात मैं उसी समय अन्य प्रयोजनों के लिए एपीआई का उपयोग कर रहा हूं, इसलिए मैं उस सीमा तक नहीं पहुंचना चाहते हैं जो वास्तव में थोड़ा अधिक है।
बेंजामिन

जवाबों:


25

GNU सिस्टम पर और यदि आपके पास है pv, तो आप कर सकते हैं:

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

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

-P20सबसे 20 पर अमल करने के लिए है $cmdएक ही समय में।

-L10 दर को प्रति सेकंड 10 बाइट्स तक सीमित करता है, इसलिए प्रति सेकंड 5 लाइनें।

यदि आपका $cmdएस दो धीमा हो जाता है और 20 सीमा तक पहुंचने का कारण बनता है, तो कम से कम रिटर्न पर xargsएक $cmdउदाहरण तक पढ़ना बंद कर देगा । pvअभी भी पाइप पर उसी दर से लिखना जारी रहेगा, जब तक कि पाइप पूरा नहीं हो जाता (जो कि लिनक्स पर 64KiB के डिफ़ॉल्ट पाइप आकार के साथ लगभग 2 घंटे का समय लगेगा)।

उस बिंदु पर, pvलिखना बंद कर देंगे। लेकिन फिर भी, जब xargsपढ़ना फिर से शुरू होता है, तो pvवह कोशिश करेगा और पकड़ लेगा और वह सभी लाइनें भेजेगा जो उसे पहले जितनी जल्दी संभव हो उतनी जल्दी भेजनी चाहिए ताकि कुल मिलाकर प्रति सेकंड 5 लाइनों को बनाए रखा जा सके।

इसका मतलब यह है कि जब तक कि 20 प्रक्रियाओं के साथ यह संभव है कि 5 प्रति सेकंड औसत आवश्यकता पर पूरा किया जाए, तो वह ऐसा करेगा। हालाँकि जब सीमा पूरी हो जाती है, तो जिस दर से नई प्रक्रियाएँ शुरू की जाती हैं, वह pv के टाइमर से नहीं, बल्कि उस दर से चलती है जिस पर पहले cmd इंस्टेंस वापस आता है। उदाहरण के लिए, यदि 20 वर्तमान में चल रहे हैं और 10 सेकंड के लिए हैं, और उनमें से 10 एक ही समय में समाप्त करने का निर्णय लेते हैं, तो 10 नए एक ही बार शुरू किए जाएंगे।

उदाहरण:

$ 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

औसतन, यह प्रति सेकंड 5 गुना होगा भले ही दो रन के बीच देरी हमेशा 0.2 सेकंड नहीं होगी।

के साथ ksh93(या zshयदि आपका sleepआदेश आंशिक सेकंड का समर्थन करता है):

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

your-commandहालांकि समवर्ती एस की संख्या पर कोई सीमा नहीं है ।


थोड़ा परीक्षण करने के बाद, pvकमांड वही प्रतीत होता है जो मैं देख रहा था, बेहतर उम्मीद नहीं कर सकता! बस इस लाइन पर: क्या yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" shअंतिम shअतिरेक नहीं है?
बेंजामिन

1
यही कारण है कि दूसरे @Benjamin shके लिए है $0अपने में $cmdस्क्रिप्ट। यह शेल द्वारा त्रुटि संदेशों में भी उपयोग किया जाता है। इसके बिना, $0हो जाएगा yसे yesहै, तो आप की तरह त्रुटि संदेश प्राप्त होता है y: cannot execute cmd... आप भी कर सकता हैyes sh | pv -qL15 | xargs -n1 -P20 sh -c "$cmd"
स्टीफन Chazelas

मैं पूरी बात को समझने योग्य टुकड़ों में विघटित करने के लिए संघर्ष कर रहा हूँ, टीबीएच! अपने उदाहरण में, आपने इसे अंतिम रूप से हटा दिया है sh; और मेरे परीक्षणों में, जब मैं इसे हटाता हूं, तो मुझे कोई अंतर नहीं दिखाई देता है!
बेंजामिन

@Benjamin। यह महत्वपूर्ण नहीं है। यह केवल एक अलग बना देगा अगर आपका $cmdउपयोग करता है $0(यह क्यों होगा?) और त्रुटि संदेशों के लिए। उदाहरण के लिए प्रयास करें cmd=/; दूसरे के बिना sh, आपको y: 1: y: /: Permission deniedइसके बजाय कुछ ऐसा दिखाई देगाsh: 1: sh: /: Permission denied
स्टीफन चेज़लस

मुझे आपके समाधान के साथ एक समस्या हो रही है: यह कुछ घंटों के लिए ठीक काम करता है, फिर कुछ बिंदु पर यह बिना किसी त्रुटि के बस बाहर निकलता है। क्या यह पाइप के पूर्ण होने से संबंधित हो सकता है, कुछ अप्रत्याशित दुष्प्रभाव हो सकते हैं?
बेंजामिन

4

सरलीकृत रूप से, यदि आपकी कमांड 1 सेकंड से कम समय तक रहती है तो आप प्रत्येक सेकंड में 5 कमांड शुरू कर सकते हैं। जाहिर है, यह बहुत ही धमाकेदार है।

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

यदि आपकी कमांड 1 सेकंड से अधिक समय ले सकती है और आप उन कमांड को फैलाना चाहते हैं जिन्हें आप आज़मा सकते हैं

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

वैकल्पिक रूप से, आपके पास 5 अलग-अलग लूप हो सकते हैं जो 1 सेकंड न्यूनतम के साथ स्वतंत्र रूप से चलते हैं।

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

अच्छा समाधान के रूप में अच्छी तरह से। मुझे यह पसंद है कि यह सरल है और प्रति सेकंड 5 गुना है, लेकिन इसे एक ही समय में (प्रत्येक 200ms के बजाय) 5 कमांड शुरू करने का नुकसान है, और शायद एक समय में चलने वाले अधिकांश एन थ्रेड्स में सुरक्षित होने का अभाव है !
बेंजामिन

@ बेंजामिन I ने दूसरे संस्करण के पाश में 200ms की नींद जोड़ी। इस दूसरे संस्करण में एक समय में 5 सेमी से अधिक नहीं चल सकते क्योंकि हम केवल हर 5 को शुरू करते हैं, फिर उन सभी की प्रतीक्षा करें।
मयूह

मुद्दा यह है, आपके पास प्रति सेकंड 5 से अधिक शुरुआत नहीं हो सकती है; यदि सभी स्क्रिप्ट अचानक निष्पादित करने के लिए 1s से अधिक लेती हैं, तो आप API सीमा तक पहुंचने से बहुत दूर हैं। इसके अलावा, यदि आप उन सभी की प्रतीक्षा करते हैं, तो एक एकल अवरोधन स्क्रिप्ट अन्य सभी को अवरुद्ध करेगा?
बेंजामिन

@ बैंजामिन तो आप 5 स्वतंत्र लूप चला सकते हैं, प्रत्येक में 1 सेकंड की न्यूनतम नींद होती है, तीसरा संस्करण देखें।
meuh

2

सी कार्यक्रम के साथ,

आप उदाहरण के लिए एक धागे का उपयोग कर सकते हैं जो थोड़ी देर में 0.2 सेकंड के लिए सोता है

#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;
}

एक धागा बनाने का तरीका जानने के लिए इसका उपयोग करें: एक धागा बनाएं (यह वह लिंक है जिसका उपयोग मैंने इस कोड को चिपकाने के लिए किया है)


आपके उत्तर के लिए धन्यवाद, हालाँकि मैं आदर्श रूप से ऐसी चीज़ की तलाश में था जिसमें C प्रोग्रामिंग शामिल नहीं होगी, लेकिन केवल मौजूदा यूनिक्स टूल्स का उपयोग करके!
बेंजामिन

हाँ, उदाहरण के लिए इस शक्ति को stackoverflow जवाब एक टोकन बाल्टी कई कार्यकर्ता धागे के मध्य साझा करें, लेकिन Unix.SE पर पूछ के बजाय "प्रोग्रामर" दृष्टिकोण की तलाश है :-) फिर भी, एक "पावर उपयोगकर्ता" के और अधिक पता चलता है ccहै एक मौजूदा यूनिक्स उपकरण, और यह कोड का एक बहुत कुछ नहीं है!
स्टीव जेसोप

1

नोड.जेएस का उपयोग करके आप एक एकल थ्रेड शुरू कर सकते हैं जो हर 200 मिली सेकेंड तक बैश स्क्रिप्ट को निष्पादित करता है, भले ही प्रतिक्रिया वापस आने में कितना समय लगे, क्योंकि प्रतिक्रिया कॉलबैक फ़ंक्शन के माध्यम से आती है

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);

यह जावास्क्रिप्ट प्रत्येक 200 मिलीसेकंड पर चलता है और कॉलबैक फ़ंक्शन के माध्यम से प्रतिक्रिया मिलती है function (error, stdout, stderr)

इस तरह आप नियंत्रित कर सकते हैं कि यह प्रति सेकंड 5 कॉल से अधिक कभी भी स्वतंत्र रूप से नहीं होता है कि कमांड का निष्पादन कितना धीमा या तेज है या प्रतिक्रिया के लिए कितना इंतजार करना पड़ता है।


मुझे यह समाधान पसंद है: यह नियमित अंतराल पर प्रति सेकंड 5 कमांड शुरू करता है । एकमात्र कमी जो मैं देख सकता हूं, वह यह है कि एक समय में चलने वाली अधिकांश n प्रक्रियाओं में सुरक्षित होने का अभाव है! यदि यह कुछ ऐसा है जिसे आप आसानी से शामिल कर सकते हैं? मैं नोड से परिचित नहीं हूं। जेसेज
बेंजामिन

0

मैंने pvकुछ समय के लिए स्टीफन चेज़ेलस- आधारित समाधान का उपयोग किया है , लेकिन यह पता चला है कि यह कुछ समय के बाद, कुछ मिनटों से कुछ घंटों के लिए यादृच्छिक रूप से (और चुपचाप) बाहर निकल गया। - संपादित करें: कारण यह था कि मेरी PHP स्क्रिप्ट कभी-कभार मर जाती थी क्योंकि अधिकतम निष्पादन समय सीमा 255 से अधिक हो गया था।

इसलिए मैंने एक साधारण कमांड-लाइन टूल लिखने का फैसला किया, जो वास्तव में मुझे चाहिए।

मेरे मूल लक्ष्य को प्राप्त करना उतना ही सरल है:

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

यह प्रति सेकंड लगभग 5 कमांड शुरू होता है, जब तक कि पहले से ही 20 समवर्ती प्रक्रियाएं नहीं होती हैं, जब तक कि एक स्लॉट उपलब्ध नहीं हो जाता है, तब तक यह अगले निष्पादन (एस) को छोड़ देता है।

यह उपकरण 255 की स्थिति से संवेदनशील नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.