मेरे पास निम्न सरल कार्य है जो एक स्क्रिप्ट में कई बार उपयोग किया जाता है जो एक निर्देशिका के माध्यम से पुनरावृत्त होता है और इसमें फाइलों की उम्र की जांच करता है।
function log($Message) {
$logFilePath = 'C:\logPath\myLog.txt'
$date = Get-Date -Format 'yyyyMMddHHmmss'
$logMessage = "{0}_{1}" -f $date,$Message
if(Test-Path -Path $logFilePath) {
$logFileContent = Get-Content -Path $logFilePath
} else {
$logFileContent = ''
}
$logMessage,$logFileContent | Out-File -FilePath $logFilePath
}
मुझे पता चला कि यह सब राम को खा जाता है। मुझे समझ नहीं आता क्यों। मैंने सोचा कि फ़ंक्शन चलाने के बाद फ़ंक्शन में चर का दायरा नष्ट हो जाता है। मैंने फ़ंक्शन के बहुत अंत में Remove-Variable logMessage,logFileContent,logFilePath,date
जोड़कर रैम समस्या को ठीक किया, लेकिन यह जानना चाहूंगा कि इस राम समस्या को अन्यथा कैसे हल किया जा सकता है और फ़ंक्शन के भीतर चर स्वचालित रूप से नष्ट क्यों नहीं होते हैं।
3 जवाब
Powershell या .Net में कचरा संग्रहकर्ता है, इसलिए स्मृति को मुक्त करना तत्काल नहीं है। पावरशेल में स्पीड स्क्रिप्ट के लिए कचरा संग्रह साथ ही स्मृति प्रबंधन शायद बेहतर है पॉवरशेल 7 में। मैंने आपके फ़ंक्शन को कई बार दोहराने की कोशिश की, लेकिन मेमोरी का उपयोग कुछ सौ मेग्स से ऊपर नहीं गया।
फ़ाइल में लाइन जोड़ने के लिए शायद कुछ अधिक कुशल .net तरीका है: प्रीपेन्ड "!" फ़ाइल की पहली पंक्ति की शुरुआत तक
मेरे पास एक लाइन तैयार करने का एक अजीब तरीका है। मुझे यकीन नहीं है कि यह एक बड़ी फाइल के साथ कितना अच्छा काम करेगा। 700 मेगापिक्सल फ़ाइल के साथ, वर्किंग सेट मेमोरी 76 मेगापिक्सल पर रही।
$c:file
one
two
three
$c:file = 'pre',$c:file
$c:file
pre
one
two
three
ps powershell
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
607 27 67448 76824 1.14 3652 3 powershell
[System.GC]::Collect()
कचरा संग्रहण शुरू करता है, लेकिन उसके समाप्त होने तक इंतजार नहीं करेगा जबकि [System.GC]::GetTotalMemory($true)
आरंभ करेगा और कचरा संग्रहण की प्रतीक्षा करें
हालांकि जैसा कि टिप्पणी की गई है, मैं शायद ही विश्वास कर सकता हूं कि यह फ़ंक्शन आपकी याददाश्त को बढ़ाता है, आप इसे अनुकूलित कर सकते हैं:
function log ([string]$Message) {
$logFilePath = 'C:\logPath\myLog.txt'
# prefix the message with the current date
$Message = "{0:yyyyMMddHHmmss}_{1}" -f (Get-Date), $Message
if (Test-Path -Path $logFilePath -PathType Leaf) {
# newest log entry on top: append current content
$Message = "{0}`r`n{1}" -f $Message, (Get-Content -Path $logFilePath -Raw)
}
Set-Content -Path $logFilePath -Value $Message
}
मैं सिर्फ इस बात से इंकार करना चाहता हूं कि फ़ाइल में प्रीपेन्ड करने के कारण रैम का उपयोग होता है। क्या आपने लॉग सामग्री को एक चर में संग्रहीत नहीं करने का प्रयास किया है? अर्थात।
$logMessage,(Get-Content -Path $logFilePath) | Out-File -FilePath $logFilePath
5/8/20 संपादित करें - पता चलता है कि प्रीपेन्डिंग (जब कुशलतापूर्वक किया जाता है) उतना धीमा नहीं है जितना मैंने सोचा था - यह उसी क्रम में है जैसे -Append
का उपयोग करना। हालांकि कोड (वह js2010) इंगित किया गया) लंबा और बदसूरत है, लेकिन अगर आपको वास्तव में फ़ाइल को प्रीपेन्ड करने की ज़रूरत है, तो इसे करने का यह तरीका है।
मैंने ओपी के कोड को स्वचालित रूप से एक नई लाइन डालने के लिए थोड़ा सा संशोधित किया।
function log-prepend{
param(
$content,
$filePath = 'C:\temp\myLogP.txt'
)
$file = get-item $filePath
if(!$file.exists){
write-error "$file does not exist";
return;
}
$filepath = $file.fullname;
$tmptoken = (get-location).path + "\_tmpfile" + $file.name;
write-verbose "$tmptoken created to as buffer";
$tfs = [System.io.file]::create($tmptoken);
$fs = [System.IO.File]::Open($file.fullname,[System.IO.FileMode]::Open,[System.IO.FileAccess]::ReadWrite);
try{
$date = Get-Date -Format 'yyyyMMddHHmmss'
$logMessage = "{0}_{1}`r`n" -f $date,$content
$msg = $logMessage.tochararray();
$tfs.write($msg,0,$msg.length);
$fs.position = 0;
$fs.copyTo($tfs);
}
catch{
write-verbose $_.Exception.Message;
}
finally{
$tfs.close();
$fs.close();
if($error.count -eq 0){
write-verbose ("updating $filepath");
[System.io.File]::Delete($filepath);
[System.io.file]::Move($tmptoken,$filepath);
}
else{
$error.clear();
[System.io.file]::Delete($tmptoken);
}
}
}
यहाँ मेरा मूल उत्तर था जो दिखाता है कि स्टॉपवॉच का उपयोग करके समय का परीक्षण कैसे किया जाता है।
जब आप किसी लॉग फ़ाइल को प्रीपेन्ड करते हैं, तो आप पूरी लॉग फ़ाइल को मेमोरी में पढ़ रहे होते हैं, फिर उसे वापस लिख रहे होते हैं।
आपको वास्तव में एपेंड का उपयोग करना चाहिए - जिससे स्क्रिप्ट बहुत तेज चलेगी।
function log($Message) {
$logFilePath = 'C:\logPath\myLog.txt'
$date = Get-Date -Format 'yyyyMMddHHmmss'
$logMessage = "{0}_{1}" -f $date,$Message
$logMessage | Out-File -FilePath $logFilePath -Append
}
संपादित करें: आपको यह समझाने के लिए कि लॉग फ़ाइल के लिए तैयार करना एक बुरा विचार है, यहाँ एक परीक्षण है जो आप अपने सिस्टम पर कर सकते हैं:
function logAppend($Message) {
$logFilePath = 'C:\temp\myLogA.txt'
$date = Get-Date -Format 'yyyyMMddHHmmss'
$logMessage = "{0}_{1}" -f $date,$Message
$logMessage | Out-File -FilePath $logFilePath -Append
}
function logPrepend($Message) {
$logFilePath = 'C:\temp\myLogP.txt'
$date = Get-Date -Format 'yyyyMMddHHmmss'
$logMessage = "{0}_{1}" -f $date,$Message
if(Test-Path -Path $logFilePath) {
$logFileContent = Get-Content -Path $logFilePath
} else {
$logFileContent = ''
}
$logMessage,$logFileContent | Out-File -FilePath $logFilePath
}
$processes = Get-Process
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
foreach ($p in $processes)
{
logAppend($p.ProcessName)
}
$stopwatch.Stop()
$stopwatch.Elapsed
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
foreach ($p in $processes)
{
logPrepend($p.ProcessName)
}
$stopwatch.Stop()
$stopwatch.Elapsed
मैंने इसे कई बार चलाया है जब तक कि मुझे लॉग फ़ाइल में कुछ हज़ार लाइनें नहीं मिलीं। से जा रहे हैं: 1603 से 1925 लाइनें, मेरे परिणाम थे:
संलग्न करें: 7.0167008 s प्रीपेन्ड: 21.7046793 s
संबंधित सवाल
जुड़े हुए प्रश्न
नए सवाल
function
एक फ़ंक्शन (इसे एक प्रक्रिया, विधि, सबरूटीन या रूटीन भी कहा जाता है) एक एकल, विशिष्ट कार्य को करने के उद्देश्य से कोड का एक हिस्सा है। इस टैग का उपयोग उन प्रश्नों के लिए करें जिनमें विशेष रूप से कार्य करना या कॉल करना शामिल है। किसी कार्य को करने के लिए फ़ंक्शन को लागू करने में मदद के लिए, इसके बजाय [एल्गोरिथ्म] या कार्य-विशिष्ट टैग का उपयोग करें।
Theo
ने बताया, आप एक ऐसी फ़ाइल में पढ़ रहे हैं जो लगातार बड़ी होती जाती है। सामग्री को प्री-पेंड करने के लिए अपनी अजीब आवश्यकता को छोड़ दें, संलग्न करें पर स्विच करें, और आपका लॉग फ़ंक्शन रैम की लगातार बढ़ती मात्रा का उपयोग करना बंद कर देगा।