স্ট্রিম হিসাবে পাওয়ারশেলের লাইন-বাই-লাইনে কোনও ফাইল কীভাবে প্রক্রিয়াকরণ করা যায়


90

আমি কয়েকটি মাল্টি-গিগাবাইট পাঠ্য ফাইলের সাথে কাজ করছি এবং পাওয়ারশেল ব্যবহার করে সেগুলি নিয়ে কিছু স্ট্রিম প্রসেসিং করতে চাই। এটি সহজ স্টাফ, কেবল প্রতিটি লাইনকে বিশ্লেষণ করে এবং কিছু ডেটা বের করে, তারপরে এটি একটি ডাটাবেসে সঞ্চয় করে।

দুর্ভাগ্যক্রমে, get-content | %{ whatever($_) }পাইপের এই পর্যায়ে সম্পূর্ণ রেখাগুলি মেমরির মধ্যে রাখতে দেখা যায়। এটি আশ্চর্যজনকভাবে ধীরে ধীরে, আসলে এটি সমস্ত কিছু পড়তে খুব দীর্ঘ সময় নেয়।

সুতরাং আমার প্রশ্ন দুটি অংশ:

  1. আমি কীভাবে এটিকে স্ট্রিম লাইনটি রেখার মাধ্যমে প্রক্রিয়াকরণ করতে এবং পুরো জিনিসটিকে মেমরিতে বাফার না করে রাখতে পারি? আমি এই উদ্দেশ্যে র‌্যামের কয়েকটি জিগ ব্যবহার করা এড়াতে চাই।
  2. আমি কীভাবে এটি দ্রুত চালাতে পারি? পাওয়ারশেল পুনরুক্তি করা get-contentএকটি সি # স্ক্রিপ্টের চেয়ে 100x ধীর গতির বলে মনে হচ্ছে।

আমি আশা করছি এখানে বোবা কিছু করছি, যেমন -LineBufferSizeপ্যারামিটার বা কিছু হারিয়ে যাওয়া ...


9
গতি get-contentবাড়ানোর জন্য, 512 এ রিডকাউন্ট সেট করুন Note নোট করুন যে এই মুহুর্তে, ফরচ এ $ _ স্ট্রিংগুলির একটি অ্যারে হবে।
কিথ হিল

4
তবুও, আমি রোমানের .NET রিডারটি ব্যবহার করার পরামর্শটি দিয়েছিলাম - আরও দ্রুত faster
কিথ হিল

কৌতূহলের বাইরে, আমি যদি গতি সম্পর্কে চিন্তা না করি তবে কেবল স্মৃতি? সম্ভবত আমি। নেট পাঠকের পরামর্শ নিয়ে যাব, তবে কীভাবে পুরো পাইপটিকে স্মৃতিতে বাফার করা থেকে রক্ষা করা যায় তা জানতে আগ্রহী।
স্কোবি

7
বাফারিং কমানোর Get-Contentজন্য কোনও ভেরিয়েবলের ফলাফল নির্ধারণ করা এড়ান কারণ এটি পুরো ফাইলটিকে মেমোরিতে লোড করবে। ডিফল্টরূপে, একটি পাইপলাইনে, Get-Contentফাইলটি একবারে এক লাইনে প্রক্রিয়া করে। যতক্ষণ আপনি ফলাফল সংগ্রহ করছেন না বা একটি অভ্যন্তরীণভাবে জমা হওয়া কোনও সেমিডলেট ব্যবহার করছেন না (যেমন বাছাই-অবজেক্ট এবং গ্রুপ-অবজেক্ট) তবে মেমরির আঘাত খুব খারাপ হওয়া উচিত নয়। ফরচ-অবজেক্ট (%) হ'ল প্রতিটি লাইনকে একবারে প্রক্রিয়া করার নিরাপদ উপায়।
কিথ হিল

4
@ dwarfsoft- এর কোনও অর্থ হয় না। -অ্যান্ড ব্লকটি সমস্ত প্রক্রিয়াজাতকরণ শেষ হওয়ার পরে একবারে চলবে। আপনি দেখতে পাচ্ছেন যে আপনি যদি চেষ্টা করার চেষ্টা করেন get-content | % -End { }তবে এটি অভিযোগ করে কারণ আপনি কোনও প্রক্রিয়া ব্লক সরবরাহ করেন নি। সুতরাং এটি ডিফল্টরূপে - এবং ব্যবহার করা যাবে না, এটি অবশ্যই ডিফল্টরূপে ব্যবহার করা উচিত using এবং চেষ্টা করুন 1..5 | % -process { } -end { 'q' }এবং দেখুন যে ব্লকটি কেবল একবারই ঘটেছিল, gc | % { $_ }স্ক্রিপ্টব্লকটি ইতি-পূর্বের জন্য ডিফল্ট হয়ে থাকলে স্বাভাবিকভাবে কাজ করবে না ...
টেসেল্ল্যাটিংহেকলার

উত্তর:


93

আপনি যদি সত্যিই মাল্টি-গিগাবিট পাঠ্য ফাইলগুলিতে কাজ করতে চলেছেন তবে পাওয়ারশেল ব্যবহার করবেন না। এমনকি যদি আপনি এটি পড়ার কোনও উপায় খুঁজে পান তবে বিপুল পরিমাণ রেখার দ্রুত প্রক্রিয়াকরণ যেভাবেই হোক পাওয়ারশেলে ধীর হবে এবং আপনি এড়াতে পারবেন না। এমনকি সাধারণ লুপগুলি ব্যয়বহুল, 10 মিলিয়ন পুনরাবৃত্তির জন্য বলুন (আপনার ক্ষেত্রে একেবারে বাস্তব):

# "empty" loop: takes 10 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) {} }

# "simple" job, just output: takes 20 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i } }

# "more real job": 107 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i.ToString() -match '1' } }

আপডেট: আপনি যদি এখনও ভীত না হন তবে। নেট পাঠকটি ব্যবহার করার চেষ্টা করুন:

$reader = [System.IO.File]::OpenText("my.log")
try {
    for() {
        $line = $reader.ReadLine()
        if ($line -eq $null) { break }
        # process the line
        $line
    }
}
finally {
    $reader.Close()
}

আপডেট 2

সম্ভবত আরও ভাল / সংক্ষিপ্ত কোড সম্পর্কে মন্তব্য আছে। মূল কোডটির সাথে কোনও ভুল নেই forএবং এটি সিউডো কোড নয়। তবে রিডিং লুপের সংক্ষিপ্ত (সংক্ষিপ্ত?) রূপটি

$reader = [System.IO.File]::OpenText("my.log")
while($null -ne ($line = $reader.ReadLine())) {
    $line
}

4
এফওয়াইআই, পাওয়ারশেল ভি 3-তে স্ক্রিপ্ট সংকলন পরিস্থিতিটি কিছুটা উন্নত করে। "রিয়েল জব" লুপটি কনসোলটিতে টাইপ করা ভি 3-তে 112 সেকেন্ড থেকে ভি 2 তে 62 সেকেন্ডে চলে গেছে। আমি যখন স্ক্রিপ্টে লুপটি রেখেছি এবং স্ক্রিপ্ট এক্সিকিউশনটি ভি 3 এ পরিমাপ করি তখন তা 34 সেকেন্ডে নেমে যায়।
কিথ হিল

আমি স্ক্রিপ্টে তিনটি পরীক্ষা রেখেছি এবং এই ফলাফলগুলি পেয়েছি: ভি 3 বিটা: 20/27/83 সেকেন্ড; ভি 2: 14/21/101। দেখে মনে হচ্ছে আমার পরীক্ষায় ভি 3 পরীক্ষা 3-তে দ্রুত তবে এটি প্রথম দুটিতে বেশ ধীর। ঠিক আছে, এটি বিটা, আশা করি আরটিএম-তে পারফরম্যান্স উন্নতি হবে।
রোমান কুজমিন

লোকেরা কেন এমন লুপে বিরতি ব্যবহার করার জন্য জোর দেয়? এমন একটি লুপ কেন ব্যবহার করবেন না যা এর প্রয়োজন হয় না, এবং আরও ভাল পড়ুন যেমন লুপটি প্রতিস্থাপনের সাথেdo { $line = $reader.ReadLine(); $line } while ($line -neq $null)
BeowulfNode42

4
উফ যে সমান না জন্য এক হতে হবে। সেই বিশেষভাবে করুন .. সেই সময়ের লুপটিতে সমস্যা রয়েছে যে ফাইলের শেষে নালটি প্রক্রিয়া করা হবে (এই ক্ষেত্রে আউটপুট)। এটিকে ঘিরে কাজ করার জন্য আপনিও থাকতে পারেনfor ( $line = $reader.ReadLine(); $line -ne $null; $line = $reader.ReadLine() ) { $line }
BeowulfNode42

4
@ BeowulfNode42, আমরা এই এমনকি খাটো করতে পারেন: while($null -ne ($line = $read.ReadLine())) {$line}। তবে বিষয়টি আসলে এই জাতীয় বিষয়গুলি নিয়ে নয়।
রোমান কুজমিন

52

System.IO.File.ReadLines()এই দৃশ্যের জন্য নিখুঁত। এটি কোনও ফাইলের সমস্ত লাইন ফেরত দেয় তবে আপনাকে অবিলম্বে রেখাগুলির উপরে পুনরাবৃত্তি শুরু করতে দেয় যার অর্থ এটি সম্পূর্ণ সামগ্রী মেমরিতে সংরক্ষণ করতে পারে না।

নেট। 4.0 বা তার চেয়ে বেশি এর প্রয়োজন।

foreach ($line in [System.IO.File]::ReadLines($filename)) {
    # do something with $line
}

http://msdn.microsoft.com/en-us/library/dd383503.aspx


6
একটি নোট প্রয়োজন:। নেট ফ্রেমওয়ার্ক - এর মধ্যে সমর্থিত: 4.5, 4 সুতরাং, এটি কিছু মেশিনে ভি 2 বা ভি 1 এ কাজ করতে পারে না।
রোমান কুজমিন

এটি আমার System.IO.File ত্রুটি বিদ্যমান নয় দিয়েছেন, কিন্তু রোমান দ্বারা উপরের কোড আমার জন্য কাজ
Kolob ক্যানিয়ন

এটি কেবল আমার প্রয়োজন ছিল এবং এটি বিদ্যমান পাওয়ারশেল স্ক্রিপ্টে সরাসরি ফেলে দেওয়া সহজ ছিল।
ব্যবহারকারী1751825

5

আপনি যদি সোজা পাওয়ারশেল ব্যবহার করতে চান তবে নীচের কোডটি দেখুন।

$content = Get-Content C:\Users\You\Documents\test.txt
foreach ($line in $content)
{
    Write-Host $line
}

16
Get-Contentবড় ফাইলগুলিতে খুব ধীর হওয়ায় ওপি এটি থেকে মুক্তি পেতে চেয়েছিল ।
রোমান কুজমিন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.