অনন্য আউটপুট ফাইলগুলিতে অনন্য ইনপুট ফাইলগুলি প্রক্রিয়া করতে সমান্তরাল ব্যবহার করে


18

আমার শেল স্ক্রিপ্টিং সমস্যা রয়েছে যেখানে আমাকে ইনপুট ফাইলগুলি (প্রতিটি ইনপুট লাইনযুক্ত প্রতিটি ফাইল) পূর্ণ একটি ডিরেক্টরি দেওয়া হয়েছে এবং তাদের প্রতিটি আউটপুট একটি অনন্য ফাইলে পুনর্নির্দেশ করা উচিত (ওরফে, file_1.input প্রয়োজন) ফাইল_1. আউটপুট, এবং এগুলিতে ক্যাপচার করা হবে)।

পূর্ব-সমান্তরাল , আমি কেবল ডিরেক্টরিতে প্রতিটি ফাইল পুনরাবৃত্তি করব এবং আমার কমান্ডটি সম্পাদন করব, প্রসেসরকে অভিভূত না করার জন্য কিছু ধরণের টাইমার / গণনা কৌশল করার সময় (ধরে নিবেন যে প্রতিটি প্রক্রিয়াটির ধ্রুব রানটাইম আছে)। তবে, আমি জানি যে সবসময় এটি হবে না, সুতরাং "সমান্তরাল" এর মতো সমাধান ব্যবহার করা কাস্টম কোড না লিখে শেল স্ক্রিপ্ট মাল্টি-থ্রেডিং পাওয়ার সেরা উপায় বলে মনে হয়।

আমি এই প্রতিটি ফাইলের প্রক্রিয়া করার জন্য সমান্তরালভাবে চাবুক দেওয়ার কিছু উপায় সম্পর্কে চিন্তাভাবনা করেছি (এবং আমাকে আমার কোরগুলি দক্ষতার সাথে পরিচালনা করতে দিয়েছি), সেগুলি সবই হ্যাকি বলে মনে হচ্ছে। আমার মনে হয় যা আমি খুব সহজ ব্যবহারের ক্ষেত্রে মনে করি তাই এটিকে যথাসম্ভব পরিষ্কার রাখা পছন্দ করি (এবং সমান্তরাল উদাহরণগুলিতে কিছুই আমার সমস্যা বলে মনে হয় না।

কোন সাহায্য প্রশংসা হবে!

ইনপুট ডিরেক্টরি উদাহরণ:

> ls -l input_files/
total 13355
location1.txt
location2.txt
location3.txt
location4.txt
location5.txt

লিপি:

> cat proces_script.sh
#!/bin/sh

customScript -c 33 -I -file [inputFile] -a -v 55 > [outputFile]

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

আমার সম্পূর্ণ প্রক্রিয়াটি চালানোর পরিবর্তে, আমি আমার পরিবেশে তার সমাধানটি প্রমাণ করার জন্য ধারণা কমান্ডের একটি প্রমাণ দিয়ে শুরু করতে পেরেছি। আমার দুটি পৃথক বাস্তবায়ন (এবং নোট) দেখুন:

find /home/me/input_files -type f -name *.txt | parallel cat /home/me/input_files/{} '>' /home/me/output_files/{.}.out

আমার ইনপুট ফাইল ডিরেক্টরিতে সমস্ত প্রযোজ্য ফাইলগুলি সন্ধান করতে (ls নয়, এটি সমস্যার কারণ হতে পারে) ব্যবহার করে এবং তার বিষয়বস্তু একটি পৃথক ডিরেক্টরি এবং ফাইলে পুনঃনির্দেশ করে। উপরের থেকে আমার সমস্যাটি পড়া এবং পুনর্নির্দেশ করা ছিল (প্রকৃত স্ক্রিপ্টটি সহজ ছিল), সুতরাং বিড়ালের সাথে স্ক্রিপ্টটি প্রতিস্থাপন করা ধারণার সূক্ষ্ম প্রমাণ ছিল।

parallel cat '>' /home/me/output_files/{.}.out :::  /home/me/input_files/*

এই দ্বিতীয় সমাধানটি ফাইলগুলি পড়তে সমান্তরালের ইনপুট ভেরিয়েবল দৃষ্টান্ত ব্যবহার করে তবে কোনও নবজাতকের জন্য, এটি ছিল আরও বিভ্রান্তিকর। আমার জন্য, একটি পাইপ ব্যবহার করে আমার প্রয়োজনীয়তা ঠিক ঠিক পূরণ করা গেল।

উত্তর:


27

GNU সমান্তরাল এই ধরণের কাজের জন্য ডিজাইন করা হয়েছে:

parallel customScript -c 33 -I -file {} -a -v 55 '>' {.}.output ::: *.input

বা:

ls | parallel customScript -c 33 -I -file {} -a -v 55 '>' {.}.output

এটি সিপিইউ কোর প্রতি একটি কাজ চালাবে।

আপনি জিএনইউ সমান্তরাল সহজেই এটি ইনস্টল করতে পারেন:

wget https://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem

আরও জানতে জিএনইউ সমান্তরালের জন্য অন্তর্ভুক্ত ভিডিওগুলি দেখুন: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1


দুর্দান্ত উত্তর (এবং সমান্তরাল ব্যবহারের জন্য আমার অনুরোধটি পড়ার জন্য প্রধান পয়েন্ট)।
জে জোন্স 3

5

এটি করার স্ট্যান্ডার্ড উপায় হ'ল একটি সারি সেটআপ করা এবং এমন কোনও সংখ্যক কর্মী স্প্যান করা যা কীভাবে সারি থেকে কোনও জিনিস টানতে পারে এবং প্রক্রিয়াজাত করতে জানে। এই প্রক্রিয়াগুলির মধ্যে যোগাযোগের জন্য আপনি একটি ফিফো (ওরফে নামযুক্ত পাইপ) ব্যবহার করতে পারেন।

ধারণাটি প্রদর্শনের জন্য নীচে একটি নির্বোধ উদাহরণ is

একটি সাধারণ সারির স্ক্রিপ্ট:

#!/bin/sh
mkfifo /tmp/location-queue
for i in inputfiles/*; do
  echo $i > /tmp/location-queue
done
rm /tmp/location-queue

এবং একজন শ্রমিক:

#!/bin/sh
while read file < /tmp/location-queue; do
  process_file "$file"
done

process_file আপনার কর্মী কোথাও সংজ্ঞায়িত হতে পারে, এবং এটি আপনার যা প্রয়োজন তা করতে পারে।

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

মনিটর স্ক্রিপ্ট:

#!/bin/sh
queue.sh &
num_workers="$1"
i=0
while [ $i < $num_workers ]; do
  worker.sh &
  echo $! >> /tmp/worker.pids
  i=$((i+1))
done
monitor_workers

ওখানে তোমার আছে। যদি আপনি প্রকৃতপক্ষে এটি করেন তবে মনিটরে ফিফো সেটআপ করা ভাল এবং কাতারে এবং কর্মী উভয়ের পক্ষে পথটি উত্তোলন করা ভাল, যাতে তারা মিলিত হয় না এবং ফিফোর কোনও নির্দিষ্ট স্থানে আটকে থাকে না। আমি উত্তরে এটি নির্দিষ্টভাবে সেট আপ করেছি যাতে এটি স্পষ্ট হয় যে আপনি এটি পড়ার সময় কী ব্যবহার করছেন।


মনিটর কীভাবে নতুন কর্মীদের উপরের কাজ শেষ না হওয়া অবধি সাময়িকভাবে থামিয়ে দিতে পারে (ওরফে, আমি কখনই হ্রাস পেতে পারি)? ---- আমার নিজের সম্পাদনার উত্তরে, শ্রমিকরা কখনই দূরে যায় না, সমস্ত প্রসেসিং শেষ না হওয়া অবধি তারা কেবল ফাইলগুলি প্রক্রিয়া করে (সুতরাং সেই সাথে 'প্রসেসরের মধ্যেও লুপ)।
জে জোন্স

মনিটরের স্ক্রিপ্টের শেষে "মনিটর_ওয়ার্কার্স" লাইনটি কী করছে?
জে জোন্স

@ জোনস - monitor_workersঠিক এর মতো process_file- এটি এমন একটি ফাংশন যা আপনি যা চান তা করে। মনিটর সম্পর্কে - আপনি ঠিক বলেছেন; এটিতে তার কর্মীদের পিডগুলি সংরক্ষণ করা উচিত (যাতে এটি একটি কিল সংকেত পাঠাতে পারে) এবং যখন কোনও শ্রমিক শুরু হয় তখন কাউন্টারটিকে বাড়ানো দরকার। আমি অন্তর্ভুক্ত উত্তর সম্পাদনা করেছি।
শন জে গফ

আমি সত্যিই আপনার কাজের প্রশংসা করি, তবে আমার মনে হয় আপনার জিএনইউ ব্যবহার করা উচিত parallel। আমি মনে করি এটি আপনার ধারণা, সম্পূর্ণরূপে বাস্তবায়িত।
মোটোবি

5

আরেকটি উদাহরণ:

ls *.txt | parallel 'sort {} > {.}.sorted.txt'

আমি অন্যান্য উদাহরণগুলি অপ্রয়োজনীয়ভাবে জটিল দেখতে পেয়েছি, যখন বেশিরভাগ ক্ষেত্রে উপরেরটি যা আপনি অনুসন্ধান করে যাচ্ছেন।


4

সমান্তরালকরণ করতে পারে এমন একটি সাধারণ উপলব্ধ সরঞ্জামটি হ'ল মেক। জিএনইউ মেক এবং আরও কয়েকজনের -jকাছে সমান্তরাল বিল্ড সম্পাদন করার বিকল্প রয়েছে।

.SUFFIXES: .input .output
.input.output:
        process_one_file <$< >$@.tmp
        mv -f $@.tmp $@

এইভাবে চালান make(আমি ধরেছি আপনার ফাইলের নামগুলিতে কোনও বিশেষ অক্ষর নেই, makeসেগুলির সাথে ভাল নয়):

make -j 4 $(for x in *.input; do echo ${x%.*}.output; done)

imho

3

বর্তমান ডিরেক্টরিতে ফাইলের একটি বড় সেটে একই কমান্ডটি সম্পাদন করা:

#!/bin/sh
trap 'worker=`expr $worker - 1`' USR1  # free up a worker
worker=0  # current worker
num_workers=10  # maximum number of workers
for file in *.txt; do
    if [ $worker -lt $num_workers ]; then
        {   customScript -c 33 -I -file $file -a -v 55 > `basename $file .txt`.outtxt 
            kill -USR1 $$ 2>/dev/null  # signal parent that we're free
        } &
        echo $worker/$num_worker $! $file  # feedback to caller
        worker=`expr $worker + 1`
    else
        wait # for a worker to finish
    fi
done

এটি ফাইলের মধ্যে আউটপুট রেখে customScriptপ্রতিটি txtফাইল চালায় outtxtfiles আপনার প্রয়োজন অনুসারে পরিবর্তন করুন। এটি কাজ করার মূল বিষয় হ'ল সিগন্যাল প্রসেসিং, SIGUSR1 ব্যবহার করে যাতে শিশু প্রক্রিয়া পিতামাতাকে জানায় যে এটি সম্পন্ন হয়েছে। SIGCHLD ব্যবহার করা কার্যকর হবে না কারণ স্ক্রিপ্টের বেশিরভাগ বিবৃতিগুলি শেল স্ক্রিপ্টে SIGCHLD সংকেত তৈরি করে। আপনার কমান্ডের পরিবর্তে আমি এটি চেষ্টা করেছি sleep 1, প্রোগ্রামটি ব্যবহারকারীর সিপিইউর 0.28s এবং সিস্টেম সিপিইউর 0.14s ব্যবহার করেছে; এটি প্রায় 400 টি ফাইলের মধ্যে ছিল।


বর্তমানে অপেক্ষা করা একই ফাইলটি গ্রহণ করার জন্য 'অপেক্ষা' কীভাবে যথেষ্ট স্মার্ট এবং "যদি" বিবৃতিতে ভাইবোনটি পুনরায় প্রবেশ করতে পারে?
জে জোন্স

এটি waitযথেষ্ট 'স্মার্ট' নয়; তবে এটি SIGUSR1সংকেত পাওয়ার পরে ফিরে আসবে । শিশু / শ্রমিক SIGUSR1পিতামাতার কাছে একটি প্রেরণ করে, যা ধরা পড়ে ( trap), এবং হ্রাস $worker( trapধারা) এবং waitএই if [ $worker -lt $num_workers ]ধারাটি কার্যকর করার অনুমতি দিয়ে অস্বাভাবিকভাবে ফিরে আসে ।
আর্জেজ

0

বা সহজভাবে ব্যবহার করুন xargs -P, অ্যাডিটোনাল সফ্টওয়্যার ইনস্টল করার দরকার নেই:

find . -type f -print0 | xargs -0 -I'XXX' -P4 -n1 custom_script -input "XXX" -output "XXX.out"

বিকল্পগুলির জন্য কিছুটা ব্যাখ্যা:

  • -I'XXX' স্ট্রিং সেট করে যা ফাইলের নাম সহ কমান্ড টেমপ্লেটে প্রতিস্থাপন করা হবে
  • -P4 সমান্তরালে 4 প্রক্রিয়া চালানো হবে
  • -n1 দুটি এক্সএক্সএক্স পাওয়া গেলেও মৃত্যুদণ্ড কার্যকর করাতে কেবল একটি ফাইল রাখবে
  • -print0এবং -0একসাথে কাজ করুন, আপনাকে ফাইলের নামেরগুলিতে বিশেষ অক্ষর (সাদা স্থানের মতো) রাখতে দিন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.