Saya memiliki kode berikut:
info = new System.Diagnostics.ProcessStartInfo("TheProgram.exe", String.Join(" ", args));
info.CreateNoWindow = true;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForExit();
Console.WriteLine(p.StandardOutput.ReadToEnd()); //need the StandardOutput contents
Saya tahu bahwa output dari proses yang saya mulai sekitar 7MB. Menjalankannya di konsol Windows berfungsi dengan baik. Sayangnya secara terprogram ini hang tanpa batas di WaitForExit. Perhatikan juga kode ini TIDAK menggantung untuk output yang lebih kecil (seperti 3KB).
Apakah mungkin StandardOutput internal di ProcessStartInfo tidak dapat buffer 7MB? Jika demikian, apa yang harus saya lakukan? Jika tidak, apa yang saya lakukan salah?
c#
processstartinfo
Epaga
sumber
sumber
Jawaban:
Masalahnya adalah bahwa jika Anda mengarahkan ulang
StandardOutput
dan / atauStandardError
buffer internal dapat menjadi penuh. Apa pun pesanan yang Anda gunakan, mungkin ada masalah:StandardOutput
proses dapat memblokir mencoba menulis untuk itu, sehingga proses tidak pernah berakhir.StandardOutput
menggunakan ReadToEnd maka proses Anda dapat memblokir jika proses tidak pernah ditutupStandardOutput
(misalnya jika tidak pernah berakhir, atau jika diblokir untuk menulisStandardError
).Solusinya adalah menggunakan pembacaan asinkron untuk memastikan bahwa buffer tidak mendapatkan penuh. Untuk menghindari kebuntuan dan mengumpulkan semua output dari keduanya
StandardOutput
danStandardError
Anda dapat melakukan ini:EDIT: Lihat jawaban di bawah ini untuk cara menghindari ObjectDisposedException jika batas waktu terjadi.
sumber
using
pernyataan untuk event handler harus di atas yangusing
pernyataan untuk proses itu sendiri?The dokumentasi untuk
Process.StandardOutput
mengatakan untuk membaca sebelum Anda menunggu jika tidak, anda bisa jalan buntu, potongan disalin di bawah ini:sumber
RedirectStandardOutput = true;
dan tidak menggunakanp.StandardOutput.ReadToEnd();
Anda mendapatkan jalan buntu / hang.Jawaban Mark Byers sangat bagus, tetapi saya hanya ingin menambahkan yang berikut:
Para delegasi
OutputDataReceived
danErrorDataReceived
perlu dihapus sebelumoutputWaitHandle
danerrorWaitHandle
dibuang. Jika proses terus menghasilkan data setelah batas waktu terlampaui dan kemudian berakhir,outputWaitHandle
danerrorWaitHandle
variabel akan diakses setelah dibuang.(FYI saya harus menambahkan peringatan ini sebagai jawaban karena saya tidak bisa mengomentari posnya.)
sumber
Ini adalah solusi berbasis TPL, Task Parallel Library (TPL) yang lebih modern untuk .NET 4.5 dan di atasnya.
Contoh Penggunaan
Penerapan
sumber
Masalah dengan ObjectDisposedException yang tidak ditangani terjadi ketika prosesnya habis. Dalam kasus seperti itu bagian lain dari kondisi:
tidak dieksekusi. Saya mengatasi masalah ini dengan cara berikut:
sumber
output
danerror
keoutputBuilder
? Bisakah seseorang tolong berikan jawaban lengkap yang berfungsi?Rob menjawabnya dan menyelamatkan saya beberapa jam dari cobaan. Baca buffer output / kesalahan sebelum menunggu:
sumber
WaitForExit()
?ReadToEnd
atau metode serupa (sepertiStandardOutput.BaseStream.CopyTo
) akan kembali setelah SEMUA data dibaca. tidak ada yang akan datang setelah ituKami memiliki masalah ini juga (atau varian).
Coba yang berikut ini:
1) Tambahkan batas waktu ke p.WaitForExit (nnnn); di mana nnnn dalam milidetik.
2) Letakkan panggilan ReadToEnd sebelum panggilan WaitForExit. Ini adalah apa yang kita lihat MS merekomendasikan.
sumber
Kredit ke EM0 untuk https://stackoverflow.com/a/17600012/4151626
Solusi lain (termasuk EM0) masih menemui jalan buntu untuk aplikasi saya, karena batas waktu internal dan penggunaan baik StandardOutput dan StandardError oleh aplikasi spawned. Inilah yang bekerja untuk saya:
Sunting: menambahkan inisialisasi StartInfo ke sampel kode
sumber
Saya memecahkannya dengan cara ini:
Saya mengarahkan ulang input, output dan error dan menangani pembacaan dari stream output dan error. Solusi ini berfungsi untuk SDK 7- 8.1, baik untuk Windows 7 dan Windows 8
sumber
Saya mencoba membuat kelas yang akan menyelesaikan masalah Anda menggunakan asynchronous stream read, dengan memperhitungkan Mark Byers, Rob, stevejay jawaban. Melakukan hal itu saya menyadari bahwa ada bug yang berhubungan dengan aliran keluaran proses asinkron yang dibaca.
Saya melaporkan bug itu di Microsoft: https://connect.microsoft.com/VisualStudio/feedback/details/3119134
Ringkasan:
Anda mungkin lebih baik menggunakan asynchronous read seperti yang disarankan oleh pengguna lain untuk kasus Anda. Tetapi Anda harus sadar bahwa Anda dapat kehilangan beberapa informasi karena kondisi balapan.
sumber
Saya kira ini adalah pendekatan yang sederhana dan lebih baik (kita tidak perlu
AutoResetEvent
):sumber
.FileName = Path + @"\ggsci.exe" + @" < obeycommand.txt"
untuk menyederhanakan kode Anda juga? Atau mungkin sesuatu yang setara"echo command | " + Path + @"\ggsci.exe"
jika Anda benar-benar tidak ingin menggunakan file obeycommand.txt yang terpisah.Tidak ada jawaban di atas yang melakukan pekerjaan.
Solusi Rob hang dan solusi 'Mark Byers' mendapatkan pengecualian dibuang (saya mencoba "solusi" dari jawaban lain).
Jadi saya memutuskan untuk menyarankan solusi lain:
Kode ini di-debug dan berfungsi dengan baik.
sumber
GetProcessOutputWithTimeout
metode.pengantar
Jawaban yang diterima saat ini tidak bekerja (melempar pengecualian) dan ada terlalu banyak solusi tetapi tidak ada kode lengkap. Ini jelas menghabiskan banyak waktu orang karena ini adalah pertanyaan yang populer.
Menggabungkan jawaban Mark Byers dan jawaban Karol Tyl, saya menulis kode lengkap berdasarkan bagaimana saya ingin menggunakan metode Process.Start.
Pemakaian
Saya telah menggunakannya untuk membuat dialog progres di sekitar perintah git. Beginilah cara saya menggunakannya:
Secara teori Anda juga dapat menggabungkan stdout dan stderr, tetapi saya belum mengujinya.
Kode
sumber
Saya tahu ini sudah lama makan malam tapi, setelah membaca seluruh halaman ini tidak ada solusi yang bekerja untuk saya, walaupun saya tidak mencoba Muhammad Rehan karena kodenya agak sulit untuk diikuti, walaupun saya kira dia berada di jalur yang benar . Ketika saya mengatakan itu tidak bekerja itu tidak sepenuhnya benar, kadang-kadang itu akan berfungsi dengan baik, saya kira itu ada hubungannya dengan panjang output sebelum tanda EOF.
Bagaimanapun, solusi yang berhasil bagi saya adalah menggunakan utas yang berbeda untuk membaca StandardOutput dan StandardError dan menulis pesan.
Semoga ini bisa membantu seseorang, yang berpikir ini bisa sangat sulit!
sumber
sw.FlushAsync(): Object is not set to an instance of an object. sw is null.
Bagaimana / di mana harussw
didefinisikan?Setelah membaca semua posting di sini, saya memutuskan pada solusi gabungan Marko Avlijaš. Namun , itu tidak menyelesaikan semua masalah saya.
Di lingkungan kami, kami memiliki Layanan Windows yang dijadwalkan untuk menjalankan ratusan file .bat .cmd .exe, ... dll. Yang berbeda yang telah terakumulasi selama bertahun-tahun dan ditulis oleh banyak orang dan gaya yang berbeda. Kami tidak memiliki kendali atas penulisan program & skrip, kami hanya bertanggung jawab untuk menjadwalkan, menjalankan, dan melaporkan keberhasilan / kegagalan.
Jadi saya mencoba hampir semua saran di sini dengan berbagai tingkat keberhasilan. Jawaban Marko hampir sempurna, tetapi ketika dijalankan sebagai layanan, itu tidak selalu menangkap stdout. Saya tidak pernah sampai ke dasar mengapa tidak.
Satu-satunya solusi yang kami temukan yang berfungsi dalam SEMUA kasus kami adalah ini: http://csharptest.net/319/using-the-processrunner-class/index.html
sumber
Solusi yang akhirnya saya gunakan untuk menghindari semua kompleksitas:
Jadi saya membuat file temp, redirect baik output dan kesalahan ke sana dengan menggunakan
> outputfile > 2>&1
dan kemudian hanya membaca file setelah proses selesai.Solusi lain baik untuk skenario di mana Anda ingin melakukan hal-hal lain dengan output, tetapi untuk hal-hal sederhana ini menghindari banyak kerumitan.
sumber
Saya sudah membaca banyak jawaban dan membuat jawaban saya sendiri. Tidak yakin yang satu ini akan memperbaiki dalam hal apapun, tetapi itu memperbaiki di lingkungan saya. Saya hanya tidak menggunakan WaitForExit dan menggunakan WaitHandle.WaitAll pada kedua output & sinyal kesalahan akhir. Saya akan senang, jika seseorang akan melihat kemungkinan masalah dengan itu. Atau jika itu akan membantu seseorang. Bagi saya itu lebih baik karena tidak menggunakan timeout.
sumber
Saya pikir dengan async, dimungkinkan untuk memiliki solusi yang lebih elegan dan tidak memiliki deadlock bahkan ketika menggunakan standardOutput dan standardError:
Ini didasarkan pada jawaban Mark Byers. Jika Anda tidak menggunakan metode async, Anda dapat menggunakannya
string output = tStandardOutput.result;
sebagai gantinyaawait
sumber
Tidak satu pun dari jawaban itu yang membantu saya, tetapi solusi ini berfungsi baik dengan menangani hang
https://stackoverflow.com/a/60355879/10522960
sumber
Posting ini mungkin sudah usang tetapi saya menemukan penyebab utama mengapa biasanya hang adalah karena stack overflow untuk redirectStandardoutput atau jika Anda memiliki redirectStandarderror.
Karena data output atau data kesalahan besar, itu akan menyebabkan waktu hang karena masih memproses untuk durasi yang tidak terbatas.
jadi untuk mengatasi masalah ini:
sumber
Mari kita sebut kode sampel yang diposting di sini pengalih dan program lain diarahkan. Jika itu saya maka saya mungkin akan menulis sebuah program tes diarahkan yang dapat digunakan untuk menduplikasi masalah.
Jadi saya lakukan. Untuk data uji saya menggunakan ECMA-334 C # Language Specificationv PDF; sekitar 5MB. Berikut ini adalah bagian penting dari itu.
Nilai data tidak cocok dengan ukuran file aktual tetapi itu tidak masalah. Tidak jelas apakah file PDF selalu menggunakan CR dan LF di akhir baris tapi itu tidak masalah untuk ini. Anda dapat menggunakan file teks besar lainnya untuk mengujinya.
Menggunakan kode redirector sampel hang ketika saya menulis sejumlah besar data tetapi tidak ketika saya menulis sejumlah kecil.
Saya mencoba sangat banyak untuk entah bagaimana melacak eksekusi kode itu dan saya tidak bisa. Saya mengomentari garis-garis program yang diarahkan yang menonaktifkan pembuatan konsol untuk program yang diarahkan untuk mencoba mendapatkan jendela konsol yang terpisah tetapi saya tidak bisa.
Kemudian saya menemukan Cara memulai aplikasi konsol di jendela baru, jendela induk, atau tanpa jendela . Jadi ternyata kita tidak dapat (dengan mudah) memiliki konsol terpisah ketika satu program konsol memulai program konsol lain tanpa ShellExecute dan karena ShellExecute tidak mendukung pengalihan, kita harus berbagi konsol, bahkan jika kita tidak menentukan jendela untuk proses lainnya.
Saya berasumsi bahwa jika program diarahkan mengisi buffer di suatu tempat maka ia harus menunggu data untuk dibaca dan jika pada saat itu tidak ada data yang dibaca oleh redirector maka itu adalah jalan buntu.
Solusinya adalah tidak menggunakan ReadToEnd dan membaca data saat data sedang ditulis tetapi tidak perlu menggunakan bacaan asinkron. Solusinya bisa sangat sederhana. Berikut ini berfungsi untuk saya dengan PDF 5 MB.
Kemungkinan lain adalah menggunakan program GUI untuk melakukan pengalihan. Kode sebelumnya berfungsi dalam aplikasi WPF kecuali dengan modifikasi yang jelas.
sumber
Saya memiliki masalah yang sama, tetapi alasannya berbeda. Namun itu akan terjadi di bawah Windows 8, tetapi tidak di bawah Windows 7. Baris berikut ini tampaknya telah menyebabkan masalah.
Solusinya adalah TIDAK menonaktifkan UseShellExecute. Saya sekarang menerima jendela popup Shell, yang tidak diinginkan, tetapi jauh lebih baik daripada program menunggu apa-apa terjadi. Jadi saya menambahkan solusi berikut untuk itu:
Sekarang satu-satunya hal yang mengganggu saya adalah mengapa ini terjadi di bawah Windows 8 di tempat pertama.
sumber
UseShellExecute
disetel ke false jika Anda ingin mengarahkan ulang output.