কীভাবে প্রতি সেকেন্ডে গড়ে 5 বার কমান্ড চালানো যায়?


21

আমার কাছে একটি কমান্ড-লাইন স্ক্রিপ্ট রয়েছে যা একটি API কল করে এবং ফলাফলগুলি সহ একটি ডাটাবেস আপডেট করে।

এপিআই সরবরাহকারীর সাথে আমার সেকেন্ডে 5 টি এপিআই কল রয়েছে limit স্ক্রিপ্টটি কার্যকর করতে 0.2 সেকেন্ডের বেশি সময় নেয়।

  • যদি আমি কমান্ডটি ধারাবাহিকভাবে চালিত করি তবে এটি যথেষ্ট দ্রুত চলবে না এবং আমি প্রতি সেকেন্ডে কেবল 1 বা 2 এপিআই কল করব।
  • যদি আমি কমান্ডটি ধারাবাহিকভাবে চালিত করি তবে একই সাথে বেশ কয়েকটি টার্মিনাল থেকে আমি 5 টি কল / দ্বিতীয় সীমা ছাড়িয়ে যেতে পারি।

থ্রেডকে অর্কেস্টেট করার কোনও উপায় যদি আমার কমান্ড-লাইন স্ক্রিপ্টটি প্রতি সেকেন্ডে প্রায় 5 বার কার্যকর হয়?

উদাহরণস্বরূপ এমন কিছু যা 5 বা 10 থ্রেড সহ চলবে এবং কোনও থ্রেড স্ক্রিপ্টটি কার্যকর করতে পারে না যদি কোনও পূর্ববর্তী থ্রেড 200 মিটারেরও কম আগে এটি চালিত করে।


উত্তরগুলির সমস্ত অনুমানের উপর নির্ভর করে যে আপনার স্ক্রিপ্টটি যেভাবে ডাকা হবে তার সাথে এটি শেষ হবে। যদি তারা অর্ডার শেষ না করে তবে কি আপনার ব্যবহারের ক্ষেত্রে এটি গ্রহণযোগ্য?
কোডি গুস্তাফসন

@ কোডি গুস্তাফসন যদি তারা অর্ডার শেষ না করে তবে এটি পুরোপুরি গ্রহণযোগ্য। আমি বিশ্বাস করি না গ্রহণযোগ্য উত্তরে এরকম অনুমান আছে, কমপক্ষে?
বেনিয়ামিন

আপনি যদি প্রতি সেকেন্ডে কল সংখ্যা ছাড়িয়ে যান? যদি API সরবরাহকারী থ্রোটল করে থাকে তবে আপনার শেষে কোনও প্রক্রিয়া দরকার নেই ... তাই না?
ফ্লোরিস

@ ফ্লোরিস তারা একটি ত্রুটি বার্তা ফেরত দেবে যা এসডিকে একটি ব্যতিক্রম হিসাবে অনুবাদ করবে। প্রথমত আমি সন্দেহ করি যে আমি প্রতি সেকেন্ডে 50 টি থ্রোটাল বার্তা উত্পন্ন করে এপিআই সরবরাহকারী খুশি হবেন (আপনারা সেই অনুসারে এই বার্তাগুলির উপর ভিত্তি করে কাজ করবেন), এবং দ্বিতীয়ত আমি একই সময়ে অন্যান্য উদ্দেশ্যে এপিআই ব্যবহার করছি, তাই আমি এমন সীমাতে পৌঁছতে চান না যা আসলে কিছুটা বেশি।
বেঞ্জামিন

উত্তর:


25

একটি জিএনইউ সিস্টেমে এবং আপনার কাছে থাকলে 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পাইপটি পূর্ণ না হওয়া অবধি এখনও পাইপগুলিতে একই হারে লিখিতভাবে চালিয়ে যাবে (যা লিনাক্সে K৪ কেবিবিইনের ডিফল্ট পাইপের আকারের সাথে প্রায় ২ ঘন্টা সময় লাগবে)।

এই মুহুর্তে, pvলেখা বন্ধ হবে। তারপরেও, xargsপুনরায় পড়া শুরু করার পরে, pvচেষ্টা করা হবে এবং যত দ্রুত সম্ভব পাঠানো উচিত সমস্ত লাইনগুলি দ্রুত পাঠানো হবে যাতে সামগ্রিকভাবে প্রতি সেকেন্ডে 5 লাইন বজায় রাখতে পারে।

এর অর্থ হ'ল যতক্ষণ পর্যন্ত 20 প্রসেসের সাথে এটি সম্ভব হিসাবে গড়ে প্রতি সেকেন্ডে 5 রান পূরণ করা সম্ভব, এটি এটি করবে। তবে সীমাটি পৌঁছে গেলে, নতুন প্রসেসগুলি যে হারে প্রসেস শুরু হয় তা পিভির টাইমার দ্বারা চালিত হবে না তবে আগের সেমিডেন্সের দৃষ্টিতে যে হারে ফিরে আসে। উদাহরণস্বরূপ, যদি বর্তমানে 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 বার হবে।

সহ 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"
Stéphane 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 সেকেন্ডের সাথে run

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

বেশ দুর্দান্ত সমাধান। আমি এটিকে পছন্দ করি এবং এটি প্রতি সেকেন্ডে ঠিক 5 বার হয় তবে এটি একই সাথে 5 টি কমান্ড শুরু করার (অসুবিধে 200 ম্যাসেজের পরিবর্তে) অসুবিধে রয়েছে এবং সম্ভবত এক সাথে বেশিরভাগ এন থ্রেড চলার সুরক্ষার অভাব রয়েছে !
বেনিয়ামিন

@ বেঞ্জামিন আমি দ্বিতীয় সংস্করণের লুপে 200 মিমি ঘুম জুড়েছি। এই দ্বিতীয় সংস্করণটিতে আমরা প্রতি 5 টি শুরু হওয়ার পরে একবারে 5 সেন্টিমিটারের বেশি চলতে পারি না, তারপরে তাদের সকলের জন্য অপেক্ষা করুন।
meuh

বিষয়টি হ'ল, প্রতি সেকেন্ডে আপনার 5 টির বেশি শুরু হতে পারে না; যদি সমস্ত স্ক্রিপ্টগুলি হঠাৎ সম্পাদন করতে 1 সেকেন্ডের বেশি সময় নেয় তবে আপনি এপিআই সীমাতে পৌঁছনো থেকে অনেক দূরে। এছাড়াও, আপনি যদি তাদের সকলের জন্য অপেক্ষা করেন, তবে একটি একক ব্লক করা স্ক্রিপ্ট অন্য সমস্তকে অবরুদ্ধ করবে?
বেনিয়ামিন

@ বেনজমিন তাই আপনি কমপক্ষে 1 সেকেন্ডের ঘুম সহ 5 টি স্বতন্ত্র লুপ চালাতে পারেন, তৃতীয় সংস্করণ দেখুন।
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;
}

কোনও থ্রেড কীভাবে তৈরি করতে হয় তা জানতে এটি ব্যবহার করুন: একটি থ্রেড তৈরি করুন (এই লিঙ্কটি আমি এই কোডটি পেস্ট করতে ব্যবহার করেছি)


আপনার উত্তরের জন্য ধন্যবাদ, যদিও আমি আদর্শভাবে এমন কিছু সন্ধান করছিলাম যা সি প্রোগ্রামিংয়ের সাথে জড়িত না, তবে কেবল বিদ্যমান ইউনিক্স সরঞ্জাম ব্যবহার করে!
বেনিয়ামিন

হ্যাঁ, এর স্ট্যাকওভারফ্লো উত্তরটি উদাহরণস্বরূপ একাধিক কর্মী থ্রেডের মধ্যে ভাগ করে নেওয়া টোকেন বালতি ব্যবহার করা হতে পারে তবে ইউনিক্সে জিজ্ঞাসা 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 টি কমান্ড শুরু করে । কেবলমাত্র ত্রুটিটি আমি দেখতে পাচ্ছি যে এটিতে বেশিরভাগ এন প্রসেসগুলি একবারে চলার কোনও সুরক্ষার অভাব রয়েছে! এটি এমন কিছু যদি আপনি সহজেই অন্তর্ভুক্ত করতে পারেন? আমি নোড.জেএস এর সাথে পরিচিত নই
বেনিয়ামিন

0

আমি স্টাফেন চ্যাজেলাস- pvভিত্তিক সমাধানটি কিছু সময়ের জন্য ব্যবহার করেছি তবে জানতে পেরেছিলাম যে এটি কিছুক্ষণ পরে কয়েক মিনিট থেকে কয়েক ঘন্টার মধ্যে এলোমেলোভাবে (এবং নিঃশব্দে) বেরিয়ে এসেছে। - সম্পাদনা করুন: কারণটি ছিল যে আমার পিএইচপি স্ক্রিপ্টটি মাঝেমধ্যে সর্বাধিক মৃত্যুর সময় অতিক্রম করার কারণে মারা যায়, স্থিতি 255 সহ প্রস্থান করে।

সুতরাং আমি একটি সাধারণ কমান্ড-লাইন সরঞ্জাম লেখার সিদ্ধান্ত নিয়েছি যা আমার যা প্রয়োজন ঠিক তা করে।

আমার আসল লক্ষ্য অর্জন করা যেমন সহজ:

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

এটি প্রতি সেকেন্ডে প্রায় ঠিক 5 টি কমান্ড শুরু করে, যদি না ইতিমধ্যে 20 সমবর্তী প্রসেস থাকে, তবে স্লট উপলব্ধ না হওয়া পর্যন্ত এটি পরবর্তী সম্পাদন (গুলি) এড়িয়ে যায়।

এই সরঞ্জামটি কোনও স্থিতির 255 প্রসঙ্গে সংবেদনশীল নয়।

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