Защо записването на стойности на клетките на Excel е бързо във VBScript, но бавно в PowerShell?

Защо писането на стойности на клетки в Excel е много по-бързо във VBScript, отколкото в PowerShell? PowerShell не е ли новото нещо, а VBScript остарелият MS скриптов език?

Пример за VBScript (запазване във filename.vbs) Това се изпълнява за част от секундата.

Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = false
Set objWorkbook = objExcel.Workbooks.Add()

' Edit: increased number of writes to 500 to make speed difference more noticeable
For row = 1 To 500
     'Edit: using .cells(row,1) instead of .cells(50,1) - this was a mistake
     objWorkbook.workSheets(1).cells(row,1).value = "test"
Next

objWorkbook.SaveAs(CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) & "\test.xlsx")
objExcel.Quit
msgbox "Done."

Пример за PowerShell (запазване във filename.ps1) Това отнема няколко секунди, за да се изпълни (проблемно при хиляди записи)

#need this to work around bug if you use a non-US locale: http://support.microsoft.com/default.aspx?scid=kb;en-us;320369
[System.Threading.Thread]::CurrentThread.CurrentCulture = "en-US" 

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $False
$xls_workbook = $excel.Workbooks.Add()

# Edit: using foreach instead of for
# Edit: increased number of writes to 500 to make speed difference more noticeable
foreach ($row in 1..500) {
    # Edit: Commented out print-line, slows down the script
    #"Row " + $row
    # This is very slow! - http://forums.redmondmag.com/forums/forum_posts.asp?tid=4037&pn=7
    $xls_workbook.sheets.item(1).cells.item($row,1) = "test"
}

$xls_workbook.SaveAs($MyInvocation.MyCommand.Definition.Replace($MyInvocation.MyCommand.Name, "") + "test.xlsx")
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

Искам да използвам това за хиляди записи. Ако няма бърз начин да направите това, PowerShell не е опция. Има ли по-добри алтернативи?


person Wouter    schedule 16.10.2012    source източник
comment
повече мощност обикновено идва с повече нужди от ресурси stackoverflow. com/questions/9343413/   -  person Slai    schedule 08.08.2017


Отговори (5)


Можете да ускорите нещата, като не преминавате през отделни клетки:

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $True
$xls_workbook = $excel.Workbooks.Add()

$range = $xls_workbook.sheets.item(1).Range("A1:A100")
$range.Value2 = "test"

Ако искате да напишете масив от стойности в диапазон, ето хубава публикация в блога, която демонстрира подобна техника:

Как да получите данни в електронна таблица на Excel много бързо с PowerShell

person Anonimista    schedule 16.10.2012
comment
Добре, предполагам, че връзката към Array-Attempt направи това решение, но наистина бих искал да знам дали PS е по-бърз с него в сравнение с array-решение във VB. @Wouter - би било хубаво, ако можете да публикувате нови резултати за сравнение. - person Jook; 17.10.2012
comment
Въпреки че всъщност не е отговорът на въпроса, ще го маркирам като приет отговор. Постига това, което исках да направя; писане бързо, в Excel, от PowerShell. Ще предположа, че писането клетка по клетка някак си не е начинът да го направите в PowerShell, докато работи във VBScript. Изглежда като стъпка назад в използваемостта за PowerShell срещу VBScript. Ако някой има обяснение за разликата в скоростта, не се колебайте да ме уведомите! - person Wouter; 17.10.2012
comment
@Jook - Тествах метода Range с до 1 000 000 записа в PS и VBS, и в двата случая отнема около 3 секунди, така че разликата във времето, ако има такава, е незначителна. Освен това показва, че методът Range също е по-добрият метод за използване във VBScript, тъй като би отнел много време с метода Cell. - person Wouter; 17.10.2012

някои неща не се вписват тук:

вашият VBScript, пише върху ЕДНА клетка отново и отново, докато вашият код на PowerShell пише в 100 клетки

objWorkbook.workSheets(1).cells(50,1).value = "test"

$xls_workbook.sheets.item(1).cells.item($row,1) = "test"

изпълнявате "Row " + $row на PowerShell - това също може да компенсира сравнението.

Ако искате да пишете в множество клетки, трябва да помислите за използване на масиви и писане върху цели диапазони, защото това има по-добра производителност.

person Jook    schedule 16.10.2012
comment
Не съм изпълнявал версията на VBScript, но със 100 записа изходът "Row " + $row добавя около половин секунда (общото време на изпълнение беше под 5 секунди за мен). - person alroc; 16.10.2012
comment
трябва да стартирате правилно версията на VBScript - запълването на единични клетки е убиец на производителността и при VB - на моята машина това отне около секунда - без частта за запазване (i7@3,4GHz 8GB Ram). - person Jook; 16.10.2012
comment
Изпълнявайки коригирания VBS (използвайки row вместо 50), получих 1,391 секунди - 3 пъти по-бързо от версията на PowerShell. - person alroc; 16.10.2012
comment
Хей Джук, съжалявам, (50, 1) беше грешка, което наистина трябваше да бъде ($row, 1). Също така увеличих броя на редовете до 500, за да направя разликата в скоростта по-очевидна. В моята система, с текущия скрипт, VBS завършва за около секунда, а PS за 20 секунди. С 10 000 реда vbs завършва за 9 секунди. Не искам да знам колко време ще отнеме в PS... - person Wouter; 17.10.2012
comment
това са някои резултати ;) Съжалявам, но не знам много за PS, за да ви помогна повече; +1 за въпроса ви обаче, защото ме заинтересувахте доста от решението на това. - person Jook; 17.10.2012
comment
6m 15s за изпълнение в PowerShell с 10K итерации. Четириядрен i7 с хипернишкова обработка, видях около 9% използване на процесора, което би било правилно - Excel работи възможно най-бързо. - person alroc; 17.10.2012

Можете да спестите малко време от версията на PowerShell, като елиминирате теста за цикъл for и използвате foreach.

for ($row = 1; $row -le 100; $row++)

отива:

foreach ($row in 1..100)

По този начин елиминирате сравнението и нарастването.

Но освен това моите наблюдения съвпадат с вашите (вижте коментарите ми по отговора на Jook).

person alroc    schedule 16.10.2012
comment
Благодаря за бакшиша. И все пак изглежда, че това е само незначително подобрение на скоростта, ако има такова. - person Wouter; 17.10.2012
comment
Отново и отново е доказано, че for е по-бърз от foreach. Сигурен съм, че това не е по-различно в powershell...така че би било незначително НАМАЛЯВАНЕ на скоростта хех... - person user2455808; 26.07.2019

Въпреки това все още взаимодействате с Excel чрез COM. Това добавя някои допълнителни разходи поради обработката на COMInterop.

person Skatterbrainz    schedule 22.11.2012
comment
VBScript не използва ли и COM обект? - person Wouter; 22.11.2012

PowerShell, поради самия си дизайн и използване на cmdlets, е нестандартна бъркотия, поне за основни неща. VBScript, който всеки програмист трябва да може да използва и разбира, има общ начин за извършване на основни неща, който не изисква инсталиране или включване на специални кратки команди с внедрения код. Вярвам, че това е крачка назад в много отношения.

Преди някой да ме разбие и да каже, че просто не използвам PowerShell, трябва да спомена, че имам дълга история на UNIX shell скриптове зад гърба си. PowerShell е подобен, очевидно, но за мен не е толкова добре внедрен.

Знам, че реалността диктува, че рано или късно ще свърша да използвам PowerShell - просто се надявам да се развие в по-стандартен заместител в бъдеще.

person Thumper    schedule 20.04.2013
comment
Достатъчно честно. Направих малко UNIX shell скриптове в края на 80-те години, така че мога да оценя вашата гледна точка. - person Skatterbrainz; 25.04.2013