Как мога да се справя с изхода от вторичен процес в реално време?

Опитвам се да напиша VB .NET програма, която изпълнява Perl скрипт и чете и използва стандартния изход. Бих искал да мога да обработвам всеки ред поотделно, докато се отпечатва, и съответно да актуализирам дисплея на моята програма. Ето някакъв код, който съм „написал“ (прочетете: „предимно копиран от интернет“):

Private WithEvents pscript As Process

Private Sub myProgram_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    pscript = New Process()
    pscript.StartInfo.CreateNoWindow = True
    pscript.StartInfo.FileName = "C:\perl64\bin\perl.exe"
    pscript.StartInfo.Arguments = "C:\test.pl"
    pscript.StartInfo.UseShellExecute = False
    pscript.StartInfo.RedirectStandardOutput = True
    pscript.StartInfo.RedirectStandardInput = True
    AddHandler pscript.OutputDataReceived, AddressOf pscript_output_process
    pscript.Start()
    pscript.BeginOutputReadLine()
End Sub

Private Sub pscript_output_process(sender As Object, e As DataReceivedEventArgs)
    MessageBox.Show(e.Data)
End Sub

Това работи с един проблем: програмата изчаква тестовият скрипт да се изпълни до край и след това задейства няколко събития OutputDataReceived едно след друго. Това означава, че когато го накарам да използва истинския скрипт, той вероятно няма да направи нищо в продължение на няколко часа и след това трябва да се справи с около 5000 събития наведнъж, въпреки факта, че нещата се отпечатват на доста редовни интервали през това време.

Има ли някакъв начин да го накарам да се справя с всеки ред текст, когато е написан, вместо с целия наведнъж в края?


person gorcq    schedule 27.04.2012    source източник
comment
Това вероятно не е нито тук, нито там, но в помощната документация се посочва многократно, че приложението, което обработва асинхронния изход, трябва да извика метода WaitForExit, за да се увери, че изходният буфер е изчистен   -  person ssis_ssiSucks    schedule 28.04.2012
comment
Джим: Извикването на WaitForExit кара приложението да замръзне напълно, докато скриптът приключи, а иначе работи по същия начин.   -  person gorcq    schedule 28.04.2012


Отговори (2)


Разбрах как да го поправя, като копирам повече неща от интернет. Проблемът изглежда е бил в Perl, който обикновено не изхвърля стандартния изход след всеки оператор за печат. Наистина не знам какво означава това последно изречение, но така или иначе, добавянето на ред local $| = 1; в горната част на скрипта (което го кара да изчиства автоматично стандартния изход, според сайт, който прочетох) решава проблема.

person gorcq    schedule 28.04.2012
comment
Стандартният изход на Flush е малко небрежно описание. Трябва да пише изчистване на буфера за STDOUT. За ефективност по подразбиране се използва бърз RAM буфер; данните се поставят в потока (файл, терминал, сокет) само когато буферът е пълен или ръчно изпразнен (изчистен). Настройката на $| изключва буферирането. (Обяснението ми е малко неточно, но същността е вярна; няма достатъчно място тук, за да спомена по-фините подробности.) Прочетете Страдате от буфериране? за разширена дискусия. - person daxim; 28.04.2012
comment
Благодаря ви за статията. Сега това има много повече смисъл. - person gorcq; 28.04.2012

person    schedule
comment
По някаква причина това хваща само първия отпечатан ред и все още чака докато скриптът приключи. Освен това кара програмата ми да замръзва, докато скриптът се изпълнява, поради което харесвам метода, базиран на събития (ако работи!). - person gorcq; 28.04.2012