আমি কীভাবে পাইপ সময় করতে পারি?


27

আমি timeএকটি কমান্ড চাই যা দুটি পৃথক কমান্ড একটি পাইপ আউটপুট সঙ্গে অন্য সাথে থাকে। উদাহরণস্বরূপ, নীচের দুটি স্ক্রিপ্ট বিবেচনা করুন:

$ cat foo.sh
#!/bin/sh
sleep 4

$ cat bar.sh
#!/bin/sh
sleep 2

এখন, আমি কীভাবে timeনেওয়া সময়টি রিপোর্ট করতে পারি foo.sh | bar.sh(এবং হ্যাঁ, আমি জানি পাইপটি এখানে কোনও অর্থবোধ করে না, তবে এটি কেবল উদাহরণ)? এটি যদি প্রত্যাশা মতো কাজ করে তবে আমি পাইপ ছাড়াই একটি ধারাবাহিকভাবে একটি সাবশেলে চালাচ্ছি:

$ time ( foo.sh; bar.sh )

real    0m6.020s
user    0m0.010s
sys     0m0.003s

তবে পাইপ দেওয়ার সময় আমি এটি কাজ করতে পারি না:

$ time ( foo.sh | bar.sh )

real    0m4.009s
user    0m0.007s
sys     0m0.003s

$ time ( { foo.sh | bar.sh; } )

real    0m4.008s
user    0m0.007s
sys     0m0.000s

$ time sh -c "foo.sh | bar.sh "

real    0m4.006s
user    0m0.000s
sys     0m0.000s

আমি একটি অনুরূপ প্রশ্নের মাধ্যমে পড়েছি ( একাধিক কমান্ডগুলিতে কীভাবে সময় চালানো যায় এবং ফাইলের জন্য সময় আউটপুট কীভাবে লিখব? ) এবং নির্বাহের ক্ষেত্রেও timeএককভাবে চেষ্টা করেছি :

$ /usr/bin/time -p sh -c "foo.sh | bar.sh"
real 4.01
user 0.00
sys 0.00

এমনকি যদি আমি একটি তৃতীয় স্ক্রিপ্ট তৈরি করি যা কেবল পাইপ চালায় তবে এটি কাজ করে না:

$ cat baz.sh
#!/bin/sh
foo.sh | bar.sh

এবং তারপরে সেই সময়:

$ time baz.sh

real    0m4.009s
user    0m0.003s
sys     0m0.000s

মজার বিষয় হল, timeপ্রথম কমান্ডটি সম্পন্ন হওয়ার সাথে সাথে এটি উপস্থিত হবে না। যদি আমি এতে পরিবর্তন bar.shকরি:

#!/bin/sh
sleep 2
seq 1 5

এবং তারপরে timeআবারও আমি প্রত্যাশা করছিলাম timeআউটপুটটি আগে মুদ্রিত হবে seqতবে তা নয়:

$ time ( { foo.sh | bar.sh; } )
1
2
3
4
5

real    0m4.005s
user    0m0.003s
sys     0m0.000s

দেখে মনে হচ্ছে এটির প্রতিবেদন 1 প্রিন্ট করার আগে এটি শেষ হওয়ার অপেক্ষায় থাকা সত্ত্বেও এটি timeকার্যকর করার সময়টি গণনা করে নি ।bar.sh

সমস্ত পরীক্ষাগুলি একটি আর্চ সিস্টেমে চালিত হয়েছিল এবং ব্যাশ ৪.৪.১২ (১) রিলেজ ব্যবহার করে। আমি কেবলমাত্র প্রকল্পের জন্য ব্যাশ ব্যবহার করতে পারি এটি একটি অংশ তাই এমনকি যদি zshবা অন্য কোনও শক্তিশালী শেল এটির আশেপাশে পেতে পারে তবে এটি আমার পক্ষে একটি কার্যকর সমাধান হবে না।

সুতরাং, পাইপযুক্ত কমান্ডগুলির একটি সেট চালানোর জন্য আমি কীভাবে সময় পাব? এবং, আমরা যখন এটি করছি, এটি কেন কাজ করে না? দেখে মনে হচ্ছে timeপ্রথম কমান্ডটি শেষ হওয়ার সাথে সাথেই তা প্রস্থান করা হবে। কেন?

আমি জানি আমি পৃথক সময় এরকম কিছু দিয়ে পেতে পারি:

( time foo.sh ) 2>foo.time | ( time bar.sh ) 2> bar.time

তবে আমি এখনও জানতে চাই যে এটি সম্পূর্ণরূপে একক ক্রিয়াকলাপ হিসাবে সময় দেওয়া সম্ভব কিনা।


1 এই একটি বাফার ইস্যু হবে বলে মনে হচ্ছে না, আমি স্ক্রিপ্ট চলমান চেষ্টা unbufferedএবং stdbuf -i0 -o0 -e0এবং সংখ্যার এখনও সেই আগের মুদ্রিত হয়েছে timeআউটপুট।


আপনি কি শারীরিক স্টপওয়াচ দিয়ে চেষ্টা করেছেন?
পেরিসিথিয়ন

@ পেরিসিঁথিয়ন হ্যাঁ শেষ পর্যন্ত আমি তা করেছি। এবং এটি উত্তরগুলি কী ব্যাখ্যা করে তাও দেখিয়েছিল: সময় আসলে কাজ করছে তবে (অবশ্যই যথেষ্ট এবং আমি বুঝতে পেরেছিলাম) পাইপলাইনে কমান্ডগুলি একযোগে চালিত হয় তাই নেওয়া সময়টি মূলত সবচেয়ে ধীর সময়।
টেরডন

উত্তর:


33

এটা কাজ করছে।

পাইপলাইনের বিভিন্ন অংশ একই সাথে কার্যকর করা হয়। পাইপলাইনে প্রসেসগুলি সিঙ্ক্রোনাইজ / সিরিয়ালাইজ করার একমাত্র বিষয় হ'ল আইপি, অর্থাৎ একটি প্রক্রিয়া পাইপলাইনের পরবর্তী প্রসেসে লেখা এবং পরের প্রক্রিয়াটি প্রথমটি কী লিখবে তা পড়তে পারে। তা ছাড়া তারা একে অপরের থেকে স্বাধীনভাবে সম্পাদন করছে ।

যেহেতু আপনার পাইপলাইনে প্রক্রিয়াগুলির মধ্যে কোনও পঠন বা লেখার ঘটনা ঘটছে না, তাই পাইপলাইনটি কার্যকর করার সময়টি সবচেয়ে দীর্ঘতম sleepকল।

আপনি পাশাপাশি লিখতে পারে

time ( foo.sh & bar.sh &; wait )

টেরডন চ্যাটে সামান্য কিছু সংশোধিত উদাহরণ স্ক্রিপ্ট পোস্ট করেছেন :

#!/bin/sh
# This is "foo.sh"
echo 1; sleep 1
echo 2; sleep 1
echo 3; sleep 1
echo 4

এবং

#!/bin/sh
# This is "bar.sh"
sleep 2
while read line; do
  echo "LL $line"
done
sleep 1

ক্যোয়ারীটি ছিল "কেন time ( sh foo.sh | sh bar.sh )3 + 3 = 6 সেকেন্ডের চেয়ে 4 সেকেন্ড ফিরে আসে ?"

প্রতিটি কমান্ড কার্যকর হওয়ার আনুমানিক সময় সহ কী ঘটছে তা দেখতে, কেউ এটি করতে পারে (আউটপুটটিতে আমার টীকা রয়েছে):

$ time ( env PS4='$SECONDS foo: ' sh -x foo.sh | PS4='$SECONDS bar: ' sh -x bar.sh )
0 bar: sleep 2
0 foo: echo 1     ; The output is buffered
0 foo: sleep 1
1 foo: echo 2     ; The output is buffered
1 foo: sleep 1
2 bar: read line  ; "bar" wakes up and reads the two first echoes
2 bar: echo LL 1
LL 1
2 bar: read line
2 bar: echo LL 2
LL 2
2 bar: read line  ; "bar" waits for more
2 foo: echo 3     ; "foo" wakes up from its second sleep
2 bar: echo LL 3
LL 3
2 bar: read line
2 foo: sleep 1
3 foo: echo 4     ; "foo" does the last echo and exits
3 bar: echo LL 4
LL 4
3 bar: read line  ; "bar" fails to read more
3 bar: sleep 1    ; ... and goes to sleep for one second

real    0m4.14s
user    0m0.00s
sys     0m0.10s

সুতরাং, উপসংহার, পাইপলাইন প্রথম দুই কল আউটপুট বাফার উপলব্ধ কারণে, 4 সেকেন্ড, না 6 লাগে echoমধ্যে foo.sh


1
@ স্টারডনে মানগুলি যোগফল হয় তবে স্ক্রিপ্টগুলিতে ব্যবহারকারী এবং সিস্টেমের সময় খুব কম লাগে - তারা কেবল অপেক্ষা করে, যা গণনা করে না (দেয়াল-ঘড়ির সময় ব্যতীত)।
স্টিফেন কিট

2
নোট করুন যে কিছু শাঁস বোর্ন শেল পছন্দ করে বা ksh93কেবল পাইপলাইনের শেষ উপাদানটির জন্য অপেক্ষা করে ( sleep 3 | sleep 1শেষ হবে 1 সেকেন্ড)। বোর্ন শেলটির কোনও timeকীওয়ার্ড নেই, তবে ksh93যখন চালানো হয় তখন timeসমস্ত উপাদানগুলির জন্য অপেক্ষা করা হয়।
স্টাফেন চেজেলাস

3
আমি কেবল বলছি যে কেউ sleep 10 | sleep 1এক সেকেন্ড সময় time sleep 10 | sleep 1নেয় এবং ksh93 এ 10 সেকেন্ড সময় নেয় এটি দেখে অবাক হতে পারে । বোর্নে শেলটিতে time sleep 10 | sleep 1এক সেকেন্ড সময় লাগবে, তবে আপনি নীল 9 সেকেন্ড পরে সময় আউটপুট পাবেন ( sleep 10কেবল এবং এর জন্য /usr/bin/time)।
স্টাফেন চেজেলাস

1
এটি কোনও কিছু রক্ষার বিষয়ে নয়। timeসঠিকভাবে পাইপলাইন বার, কিন্তু ksh93 মধ্যে শেলের আচরণ পরিবর্তন। (sleep 10 | sleep 1)1 সেকেন্ড time (sleep 10 | sleep 1)লাগে, 10 সেকেন্ড সময় নেয়। { (sleep 10 | sleep 1); echo x; }আউটপুট x1 সেকেন্ড পর time { (sleep 10 | sleep 1); echo x; }আউটপুট x10 সেকেন্ড পর। আপনি যদি কোনও ফাংশন এবং সময়টিতে সেই কোডটি রেখে দেন তবে একই।
স্টাফেন চেজেলাস

1
মনে রাখবেন যে, এ ksh93মত zsh( -o promptsubstএখানে), আপনি কি করতে পারেন typeset -F SECONDSএকটি কম পেতে আনুমানিক সেকেন্ডের সংখ্যা (POSIX shকোন হয়েছে SECONDS)
Stéphane Chazelas

10

এটি কি আরও ভাল উদাহরণ হতে পারে?

$ time perl -e 'alarm(3); 1 while 1;' | perl -e 'alarm(4); 1 while 1;'
Alarm clock

real    0m4.004s
user    0m6.992s
sys     0m0.004s

সমান্তরাল সম্পাদনের কারণে রিয়েল টাইমে মোট 4 সেকেন্ড এবং সিপিইউর 7 সেকেন্ড সময় নিয়ে স্ক্রিপ্টগুলি ব্যস্তলুপ 3 এবং 4 সেকেন্ডের জন্য (শ্রদ্ধা) হয় busy (কমপক্ষে আনুমানিক।)

অথবা এটা:

$ time ( sleep 2; echo) | ( read x; sleep 3 )

real    0m5.004s
user    0m0.000s
sys     0m0.000s

এগুলি সমান্তরালে চলবে না, সুতরাং নেওয়া মোট সময়টি 5 সেকেন্ড। এটি সমস্ত ঘুমাতে ব্যয় করেছে, তাই কোনও সিপিইউ সময় ব্যবহার করা হয়নি।


3

যদি আপনার কাছে থাকে তবে sysdigআপনি নির্বিচারে বিন্দুতে ট্রেসারগুলি canোকাতে পারেন , ধরে নিলে প্রয়োজনীয় লিখিত যুক্ত করতে কোডটি সংশোধন করতে পারবেন/dev/null

echo '>::blah::' >/dev/null
foo.sh | bar.sh
echo '<::blah::' >/dev/null

(তবে এটি আপনার "একক অপারেশন" প্রয়োজনীয়তা ব্যর্থ করে) এবং তারপরে জিনিসগুলি রেকর্ড করে

$ sudo sysdig -w blalog "span.tags contains blah"

এবং তারপরে আপনার কেবলমাত্র সময়সীমা রফতানি করার জন্য আপনার সম্ভবত একটি সিসডিগ ছেনি লাগবে

description = "Exports sysdig span tag durations";
short_description = "Export span tag durations.";
category = "Tracers";

args = {}

function on_init()
    ftags = chisel.request_field("span.tags")
    flatency = chisel.request_field("span.duration")
    chisel.set_filter("evt.type=tracer and evt.dir=<")
    return true
end

function on_event()
    local tags = evt.field(ftags)
    local latency = evt.field(flatency)
    if latency then
        print(tostring(tags) .. "\t" .. tonumber(latency) / 1e9)
    end
    return true
end

যা একবার আপনার sysdig/chiselsডিরেক্টরিতে ফাইল হিসাবে সংরক্ষণ করা হয় সে হিসাবে ফাইলটি spantagduration.luaব্যবহার করা যেতে পারে

$ sysdig -r blalog -c spantagduration
...

অথবা আপনি csysdigজেএসওএন আউটপুট সহ খেলতে পারেন ।

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