লুপের জন্য একটি সমান্তরাল করুন


109

আমি নীচের লিপিটি সমান্তরাল করার চেষ্টা করে যাচ্ছি, বিশেষত তিনটি লুপের জন্য প্রতিটি জন্য জিএনইউ সমান্তরাল ব্যবহার করে কিন্তু সক্ষম হয়ে উঠতে পারি নি। ফর লুপের মধ্যে থাকা 4 টি কমান্ড সিরিজটিতে চালিত হয়, প্রতিটি লুপ প্রায় 10 মিনিট সময় নেয়।

#!/bin/bash

kar='KAR5'
runList='run2 run3 run4'
mkdir normFunc
for run in $runList
do 
  fsl5.0-flirt -in $kar"deformed.nii.gz" -ref normtemp.nii.gz -omat $run".norm1.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
  fsl5.0-flirt -in $run".poststats.nii.gz" -ref $kar"deformed.nii.gz" -omat $run".norm2.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
  fsl5.0-convert_xfm -concat $run".norm1.mat" -omat $run".norm.mat" $run".norm2.mat"
  fsl5.0-flirt -in $run".poststats.nii.gz" -ref normtemp.nii.gz -out $PWD/normFunc/$run".norm.nii.gz" -applyxfm -init $run".norm.mat" -interp trilinear

  rm -f *.mat
done

উত্তর:


93

আপনি কেন কেবল তাদের কাঁটাচামচ করবেন না (ওরফে ব্যাকগ্রাউন্ড)?

foo () {
    local run=$1
    fsl5.0-flirt -in $kar"deformed.nii.gz" -ref normtemp.nii.gz -omat $run".norm1.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
    fsl5.0-flirt -in $run".poststats.nii.gz" -ref $kar"deformed.nii.gz" -omat $run".norm2.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
    fsl5.0-convert_xfm -concat $run".norm1.mat" -omat $run".norm.mat" $run".norm2.mat"
    fsl5.0-flirt -in $run".poststats.nii.gz" -ref normtemp.nii.gz -out $PWD/normFunc/$run".norm.nii.gz" -applyxfm -init $run".norm.mat" -interp trilinear
}

for run in $runList; do foo "$run" & done

যদি বিষয়টি পরিষ্কার না হয় তবে তাৎপর্যপূর্ণ অংশটি এখানে:

for run in $runList; do foo "$run" & done
                                   ^

পটভূমিতে একটি কাঁটাযুক্ত শেলটিতে ফাংশনটি কার্যকর করা হচ্ছে। এটি সমান্তরাল।


6
এটি যাদুর মতো কাজ করেছিল। ধন্যবাদ. এ জাতীয় একটি সহজ বাস্তবায়ন (আমাকে এখন এত বোকা মনে করে!)।
রাভনূর এস গিল

8
যদি আমার কাছে 8 টি ফাইল সমান্তরালভাবে চালিত হয় তবে কেবল 4 টি কোর, এটি কি এই জাতীয় সেটিংয়ে সংহত হতে পারে বা এর জন্য কোনও কাজের সময়সূচী প্রয়োজন?
রাভনূর এস গিল

6
আসলেই এই প্রসঙ্গে কিছু যায় আসে না; সিস্টেমের পক্ষে কোরগুলির চেয়ে বেশি সক্রিয় প্রক্রিয়া থাকা স্বাভাবিক। আপনার যদি অনেক ছোট কাজ থাকে তবে আদর্শভাবে আপনি কোনও সংখ্যক বা কর্মী থ্রেড <কোরের সংখ্যা দ্বারা পরিবেশন করা একটি সারিটি সরবরাহ করবেন। আমি জানি না শেল স্ক্রিপ্টিংয়ের মাধ্যমে এটি আসলে কতবার করা হয় (যার ক্ষেত্রে তারা থ্রেড হবে না, তারা স্বাধীন প্রক্রিয়া হবে) তবে অপেক্ষাকৃত কয়েকটি দীর্ঘ কাজের সাথে এটি অর্থহীন হবে। ওএস শিডিয়ুলার তাদের যত্ন নেবে।
স্বর্ণলোকগুলি

17
আপনি waitশেষে একটি কমান্ড যুক্ত করতে চাইবেন যাতে সমস্ত পটভূমি কাজ না করা পর্যন্ত মাস্টার স্ক্রিপ্টটি প্রস্থান না করে।
psusi

1
সমবর্তী প্রক্রিয়াগুলির সংখ্যা সীমাবদ্ধ করার জন্য আমি এটি কার্যকরও জরিমানা করব: আমার প্রক্রিয়াগুলি প্রতিটি প্রায় 25 মিনিটের জন্য একটি কোরের 100% সময় ব্যবহার করে। এটি 16 টি কোরের সাথে ভাগ করা সার্ভারে রয়েছে, যেখানে অনেক লোক কাজ চালাচ্ছে। আমার স্ক্রিপ্টের 23 টি কপি চালানো দরকার। আমি যদি সেগুলি একযোগে চালিয়ে থাকি তবে আমি সার্ভারটি স্য্যাম্প করি এবং এক বা দুই ঘন্টার জন্য একে অপরকে অকেজো করে রাখি (বোঝা 30 এর উপরে চলে যায়, অন্য সব কিছুই ধীর হয়ে যায়)। আমি অনুমান করি এটি দিয়ে কাজটি করা যেতে পারে niceতবে আমি জানি না এটি
কখন

149

নমুনা কাজ

task(){
   sleep 0.5; echo "$1";
}

ধারাবাহিক রান

for thing in a b c d e f g; do 
   task "$thing"
done

সমান্তরাল রান

for thing in a b c d e f g; do 
  task "$thing" &
done

এন-প্রক্রিয়া ব্যাচে সমান্তরাল রান

N=4
(
for thing in a b c d e f g; do 
   ((i=i%N)); ((i++==0)) && wait
   task "$thing" & 
done
)

এফআইএফওগুলিকে সেমোফোর হিসাবে ব্যবহার করা এবং এগুলি ব্যবহার করে তা নিশ্চিত করা যায় যে যত তাড়াতাড়ি সম্ভব নতুন প্রক্রিয়া তৈরি হয়েছে এবং একই সাথে এন প্রসেসের চেয়ে বেশি আর চলবে না। তবে এর জন্য আরও কোড দরকার।

এনএফএফও-ভিত্তিক সেমফোর দিয়ে প্রক্রিয়াগুলি:

open_sem(){
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}
run_with_lock(){
    local x
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
     ( "$@"; )
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

4
এতে থাকা লাইনটি waitমূলত সমস্ত প্রক্রিয়া চালাতে দেয়, যতক্ষণ না এটি nthপ্রক্রিয়াটিকে হিট করে , তারপরে অন্য সকলের চলমান শেষ হওয়ার জন্য অপেক্ষা করে, এটি কি ঠিক?
nnot101

যদি iশূন্য হয়, অপেক্ষা করুন। iশূন্য পরীক্ষার পরে বৃদ্ধি ।
PSkocik

2
@ naught101 হ্যাঁ। waitডাব্লু / নো আর্গ সব শিশুর জন্য অপেক্ষা করে। এটি কিছুটা অপব্যয় করে তোলে। পাইপ-ভিত্তিক-সেম্যাফোর পদ্ধতির আপনাকে আরও সাবলীল সম্মতি দেয় (আমি এটি একটি কাস্টম শেল ভিত্তিক বিল্ড সিস্টেমে -nt/ -otচেক সহ এখনই সাফল্যের সাথে ব্যবহার করেছি)
PSkocik

1
নিবন্ধন করুন টাস্কের প্রক্রিয়াটি প্রস্থান / ক্র্যাশ হয়ে যাওয়ার পরে স্থিতি (বা সেই বাইটেলেন্থ সহ কিছু) ফিফোতে আবার লেখা হয় ততক্ষণ টাস্কের রিটার্ন স্ট্যাটাসটি সেমফোরের ধারাবাহিকতার ক্ষতি করবে না।
পিএসকোকিক

1
FYI mkfifo pipe-$$কমান্ডের বর্তমান ডিরেক্টরিতে উপযুক্ত লেখার অ্যাক্সেস প্রয়োজন। সুতরাং আমি পুরো পথটি নির্দিষ্ট করতে পছন্দ করি /tmp/pipe-$$কারণ এটি সম্ভবত বর্তমান ব্যবহারকারীর জন্য বর্তমান ডিরেক্টরি যা আছে তা নির্ভর করে বরং লেখার অ্যাক্সেস উপলব্ধ। হ্যাঁ এর সমস্ত 3 টি উপস্থিতি প্রতিস্থাপন করুন pipe-$$
বায়ুওলফনোড 42

65
for stuff in things
do
( something
  with
  stuff ) &
done
wait # for all the something with stuff

এটি আসলে কাজ করে কিনা তা আপনার কমান্ডের উপর নির্ভর করে; আমি তাদের সাথে পরিচিত নই। rm *.matএকটু দ্বন্দ্ব প্রবণ দেখায় যদি এটা সমান্তরাল রান ...


2
এটি পুরোপুরি পাশাপাশি চালায়। আপনি ঠিক বলেছেন আমাকে একটি প্রক্রিয়া অন্যটির সাথে হস্তক্ষেপ না করে কাজ করার rm *.matজন্য এমন কিছুতে পরিবর্তন করতে rm $run".mat"হবে। আপনাকে ধন্যবাদ
রাভনূর এস গিল 5'13

@ রাভনূরস গিল স্ট্যাক এক্সচেঞ্জে স্বাগতম! যদি এই উত্তরটি আপনার সমস্যার সমাধান করে, দয়া করে এটির পাশের চেক চিহ্নটি টিক দিয়ে স্বীকৃত হিসাবে চিহ্নিত করুন।
গিলস

7
+1 এর জন্য wait, যা আমি ভুলে গিয়েছিলাম।
স্বর্ণিলোক

5
যদি প্রচুর পরিমাণে 'জিনিস' থাকে তবে এটি কি প্রচুর প্রক্রিয়া শুরু করবে না? একসাথে কেবল একটি বুদ্ধিমান সংখ্যক প্রক্রিয়া শুরু করা ভাল, তাই না?
ডেভিড ডরিয়া

1
খুব সহায়ক টিপ! এই ক্ষেত্রে থ্রেডের সংখ্যা কীভাবে সেট আপ করবেন?
দাদং জাং

30
for stuff in things
do
sem -j+0 ( something
  with
  stuff )
done
sem --wait

এটি semaphores ব্যবহার করবে, উপলব্ধ কোরের সংখ্যা হিসাবে বহু পুনরাবৃত্তিকে সমান্তরাল করে (-j +0 এর অর্থ আপনি N + 0 জবকে সমান্তরাল করে তুলবেন , যেখানে N উপলব্ধ কোরগুলির সংখ্যা )।

sem --wait কোডটির ধারাবাহিক রেখাগুলি কার্যকর করার আগে লুপের জন্য সমস্ত পুনরাবৃত্তি নির্বাহের অবসান না হওয়া পর্যন্ত অপেক্ষা করতে বলে।

দ্রষ্টব্য: আপনার জিএনইউ সমান্তরাল প্রকল্পের "সমান্তরাল" দরকার হবে (sudo apt-get ইনস্টল সমান্তরাল)।


1
এটা কি 60 পেরিয়ে যাওয়া সম্ভব? খনি যথেষ্ট ফাইল বর্ণনাকারী না বলে ত্রুটি ছুঁড়েছে।
chovy

যদি কারও জন্য বন্ধনীগুলির কারণে এটি একটি সিনট্যাক্স ত্রুটি ছুঁড়ে ফেলেছে তবে মরিটসচেফারের উত্তরটি একবার দেখুন ।
নিকোলাই 14

10

একটি সত্যিই সহজ উপায় যা আমি প্রায়শই ব্যবহার করি:

cat "args" | xargs -P $NUM_PARALLEL command

এটি একই সাথে সর্বাধিক $ NUM_PARALLEL চলমান সমান্তরালভাবে "আরগস" ফাইলের প্রতিটি লাইন পেরিয়ে কমান্ডটি চালাবে।

আপনি যদি বিভিন্ন জায়গায় ইনপুট আর্গুমেন্টগুলি বিকল্পের প্রয়োজন হয় তবে আপনি xargs এর জন্য -I বিকল্পটিও সন্ধান করতে পারেন।


6

দেখে মনে হচ্ছে fsl কাজগুলি প্রত্যেকের উপর নির্ভর করে, সুতরাং 4 টি কাজ সমান্তরালে চালানো যায় না। রানগুলি সমান্তরালে চালানো যেতে পারে।

একটি ব্যাশ ফাংশন তৈরি করুন যা একটি একক রান চালায় এবং সেই ফাংশনটি সমান্তরালভাবে চালান:

#!/bin/bash

myfunc() {
    run=$1
    kar='KAR5'
    mkdir normFunc
    fsl5.0-flirt -in $kar"deformed.nii.gz" -ref normtemp.nii.gz -omat $run".norm1.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
    fsl5.0-flirt -in $run".poststats.nii.gz" -ref $kar"deformed.nii.gz" -omat $run".norm2.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
    fsl5.0-convert_xfm -concat $run".norm1.mat" -omat $run".norm.mat" $run".norm2.mat"
    fsl5.0-flirt -in $run".poststats.nii.gz" -ref normtemp.nii.gz -out $PWD/normFunc/$run".norm.nii.gz" -applyxfm -init $run".norm.mat" -interp trilinear
}

export -f myfunc
parallel myfunc ::: run2 run3 run4

আরও জানতে ইন্ট্রো ভিডিওগুলি দেখুন: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 এবং টিউটোরিয়ালটি দিয়ে একটি ঘন্টা হাঁটুন http://www.gnu.org/software/parallel/parallel_tutorial.html আপনার আদেশ লাইন এটির জন্য আপনাকে ভালবাসবে।


আপনি যদি একটি নন-ব্যাশ শেল ব্যবহার করছেন তবে আপনাকে export SHELL=/bin/bashসমান্তরাল চলার আগেও দরকার হবে । অন্যথায় আপনি যেমন একটি ত্রুটি পাবেন:Unknown command 'myfunc arg'
অ্যান্ড্রু হার্ভে

1
@ অ্যান্ড্রু হার্ভে: শেবাং কি এটির জন্য নয়?
nnot101

5

সর্বাধিক এন-প্রক্রিয়া সমান্তরালে সমান্তরাল সম্পাদন

#!/bin/bash

N=4

for i in {a..z}; do
    (
        # .. do your stuff here
        echo "starting task $i.."
        sleep $(( (RANDOM % 3) + 1))
    ) &

    # allow only to execute $N jobs in parallel
    if [[ $(jobs -r -p | wc -l) -gt $N ]]; then
        # wait only for first job
        wait -n
    fi

done

# wait for pending jobs
wait

echo "all done"

3

আমি @lev থেকে উত্তরটি সত্যিই পছন্দ করি কারণ এটি একটি অতি সাধারণ পদ্ধতিতে সর্বাধিক সংখ্যক প্রক্রিয়ার উপর নিয়ন্ত্রণ সরবরাহ করে। তবে ম্যানুয়ালটিতে বর্ণিত হিসাবে , সেম বন্ধনীগুলির সাথে কাজ করে না।

for stuff in things
do
sem -j +0 "something; \
  with; \
  stuff"
done
sem --wait

কাজ করে।

-j + N সিপিইউ কোরের সংখ্যায় এন যুক্ত করুন। সমান্তরালভাবে এই অনেক কাজ চালান। নিবিড় নিবিড় কাজের জন্য -j +0 কার্যকর কারণ এটি এক সাথে সংখ্যার সিপিইউ-কোর কাজগুলি পরিচালনা করবে।

সিজেইউ কোরের সংখ্যা থেকে -j -N বিয়োগ করুন। সমান্তরালভাবে এই অনেক কাজ চালান। যদি মূল্যায়ন সংখ্যাটি 1 এর চেয়ে কম হয় তবে 1 ব্যবহার করা হবে। এছাড়াও - ব্যবহার-সিপাস-পরিবর্তে-কোরগুলি দেখুন।


1

আমার ক্ষেত্রে, আমি semaphore ব্যবহার করতে পারি না (আমি উইন্ডোজে গিটার-ব্যাশে আছি), তাই আমি এন শ্রমিকদের কাজ শুরু করার আগে তাদের মধ্যে বিভক্ত করার একটি জেনেরিক উপায় নিয়ে এসেছি।

কাজগুলি যদি প্রায় একই পরিমাণে সময় নেয় তবে এটি ভাল কাজ করে। অসুবিধাটি হ'ল, শ্রমিকদের মধ্যে যদি কোনও একটি তার কাজের অংশটি নিতে দীর্ঘ সময় নেয়, অন্যরা ইতিমধ্যে সমাপ্ত হয়ে সাহায্য করবে না।

এন কর্মীদের মধ্যে কাজ বিভক্ত করা (প্রতি কোর 1)

# array of assets, assuming at least 1 item exists
listAssets=( {a..z} ) # example: a b c d .. z
# listAssets=( ~/"path with spaces/"*.txt ) # could be file paths

# replace with your task
task() { # $1 = idWorker, $2 = asset
  echo "Worker $1: Asset '$2' START!"
  # simulating a task that randomly takes 3-6 seconds
  sleep $(( ($RANDOM % 4) + 3 ))
  echo "    Worker $1: Asset '$2' OK!"
}

nVirtualCores=$(nproc --all)
nWorkers=$(( $nVirtualCores * 1 )) # I want 1 process per core

worker() { # $1 = idWorker
  echo "Worker $1 GO!"
  idAsset=0
  for asset in "${listAssets[@]}"; do
    # split assets among workers (using modulo); each worker will go through
    # the list and select the asset only if it belongs to that worker
    (( idAsset % nWorkers == $1 )) && task $1 "$asset"
    (( idAsset++ ))
  done
  echo "    Worker $1 ALL DONE!"
}

for (( idWorker=0; idWorker<nWorkers; idWorker++ )); do
  # start workers in parallel, use 1 process for each
  worker $idWorker &
done
wait # until all workers are done

0

@PSkocikএর সমাধান নিয়ে আমার সমস্যা হয়েছিল । আমার সিস্টেমে জিএনইউ সমান্তরাল প্যাকেজ হিসাবে উপলব্ধ নেই এবং semআমি নিজে নিজে এটি তৈরি করে চালানোর সময় একটি ব্যতিক্রম ছুঁড়ে দিয়েছি। এরপরে আমি ফিফোর সেমোফোর উদাহরণটি চেষ্টা করেছিলাম যা যোগাযোগ সম্পর্কিত কিছু অন্যান্য ত্রুটিও ফেলেছিল।

@eyeApps xargs পরামর্শ দিয়েছিল তবে আমার জটিল ব্যবহারের ক্ষেত্রে এটি কীভাবে কাজ করতে হয় তা আমি জানতাম না (উদাহরণগুলি স্বাগত হবে)।

সমান্তরাল চাকরির জন্য আমার সমাধান যা এখানে এক সাথে চাকরির প্রক্রিয়াজাত করে যা Nকনফিগার করেছে _jobs_set_max_parallel:

_lib_jobs.sh:

function _jobs_get_count_e {
   jobs -r | wc -l | tr -d " "
}

function _jobs_set_max_parallel {
   g_jobs_max_jobs=$1
}

function _jobs_get_max_parallel_e {
   [[ $g_jobs_max_jobs ]] && {
      echo $g_jobs_max_jobs

      echo 0
   }

   echo 1
}

function _jobs_is_parallel_available_r() {
   (( $(_jobs_get_count_e) < $g_jobs_max_jobs )) &&
      return 0

   return 1
}

function _jobs_wait_parallel() {
   # Sleep between available jobs
   while true; do
      _jobs_is_parallel_available_r &&
         break

      sleep 0.1s
   done
}

function _jobs_wait() {
   wait
}

ব্যবহারের উদাহরণ:

#!/bin/bash

source "_lib_jobs.sh"

_jobs_set_max_parallel 3

# Run 10 jobs in parallel with varying amounts of work
for a in {1..10}; do
   _jobs_wait_parallel

   # Sleep between 1-2 seconds to simulate busy work
   sleep_delay=$(echo "scale=1; $(shuf -i 10-20 -n 1)/10" | bc -l)

   ( ### ASYNC
   echo $a
   sleep ${sleep_delay}s
   ) &
done

# Visualize jobs
while true; do
   n_jobs=$(_jobs_get_count_e)

   [[ $n_jobs = 0 ]] &&
      break

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