প্রস্থান কখনও কখনও প্রস্থান অপেক্ষা করার সময় স্তব্ধ হয়ে যায়


13

প্রস্থানটির অপেক্ষার সময় আমার প্রক্রিয়াটি ঝুলে থাকার কারণ কী হতে পারে?

এই কোডটিতে পাওয়ারশেল স্ক্রিপ্ট শুরু করতে হবে যা ভিতরে অনেকগুলি ক্রিয়া সম্পাদন করে যেমন এমএসবিল্ডের মাধ্যমে কোডের পুনরায় সংক্রমণের সূচনা করে, তবে সম্ভবত সমস্যাটি হ'ল এটি খুব বেশি আউটপুট উত্পন্ন করে এবং পাওয়ার শেল স্ক্রিপ্ট সঠিকভাবে কার্যকর হওয়ার পরেও প্রস্থান করার জন্য অপেক্ষা করতে গিয়ে এই কোডটি আটকে যায় probably

এটি ধরণের "অদ্ভুত" কারণ কখনও কখনও এই কোডটি সূক্ষ্মভাবে কাজ করে এবং কখনও কখনও এটি কেবল আটকে যায়।

কোডটি এখানে স্তব্ধ:

process.WaitForExit (ProcessTimeOutMiliseconds);

পাওয়ারসেল স্ক্রিপ্টটি 1-2 সেকেন্ডের মতো কার্যকর করে এর মধ্যে সময়সীমা 19 সেকেন্ড হয়।

public static (bool Success, string Logs) ExecuteScript(string path, int ProcessTimeOutMiliseconds, params string[] args)
{
    StringBuilder output = new StringBuilder();
    StringBuilder error = new StringBuilder();

    using (var outputWaitHandle = new AutoResetEvent(false))
    using (var errorWaitHandle = new AutoResetEvent(false))
    {
        try
        {
            using (var process = new Process())
            {
                process.StartInfo = new ProcessStartInfo
                {
                    WindowStyle = ProcessWindowStyle.Hidden,
                    FileName = "powershell.exe",
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    Arguments = $"-ExecutionPolicy Bypass -File \"{path}\"",
                    WorkingDirectory = Path.GetDirectoryName(path)
                };

                if (args.Length > 0)
                {
                    var arguments = string.Join(" ", args.Select(x => $"\"{x}\""));
                    process.StartInfo.Arguments += $" {arguments}";
                }

                output.AppendLine($"args:'{process.StartInfo.Arguments}'");

                process.OutputDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        outputWaitHandle.Set();
                    }
                    else
                    {
                        output.AppendLine(e.Data);
                    }
                };
                process.ErrorDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        errorWaitHandle.Set();
                    }
                    else
                    {
                        error.AppendLine(e.Data);
                    }
                };

                process.Start();

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.WaitForExit(ProcessTimeOutMiliseconds);

                var logs = output + Environment.NewLine + error;

                return process.ExitCode == 0 ? (true, logs) : (false, logs);
            }
        }
        finally
        {
            outputWaitHandle.WaitOne(ProcessTimeOutMiliseconds);
            errorWaitHandle.WaitOne(ProcessTimeOutMiliseconds);
        }
    }
}

লিপি:

start-process $args[0] App.csproj -Wait -NoNewWindow

[string]$sourceDirectory  = "\bin\Debug\*"
[int]$count = (dir $sourceDirectory | measure).Count;

If ($count -eq 0)
{
    exit 1;
}
Else
{
    exit 0;
}

কোথায়

$args[0] = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\MSBuild.exe"

সম্পাদন করা

@ ইনজেনের সমাধানে আমি একটি ছোট মোড়ক যুক্ত করেছি যা এমএস বিল্ডে ফাঁসি কার্যকর করার চেষ্টা করে

public static void ExecuteScriptRx(string path, int processTimeOutMilliseconds, out string logs, out bool success, params string[] args)
{
    var current = 0;
    int attempts_count = 5;
    bool _local_success = false;
    string _local_logs = "";

    while (attempts_count > 0 && _local_success == false)
    {
        Console.WriteLine($"Attempt: {++current}");
        InternalExecuteScript(path, processTimeOutMilliseconds, out _local_logs, out _local_success, args);
        attempts_count--;
    }

    success = _local_success;
    logs = _local_logs;
}

InternalExecuteScriptইনজেনের কোডটি কোথায়


আসলে কোন লাইনে প্রক্রিয়াটি স্তব্ধ হয়? এবং আপনার কোডটি আরও অনেক
— পরিচয়

@ মিঃ এএফ আপনি ঠিক বলেছেন - সম্পন্ন হয়েছে।
— জোয়েটি

1
পাওয়ারশেলের আসল কলিং একটি জিনিস, তবে আপনি যা সরবরাহ করছেন না তা হ'ল পাওয়ারশেলের সাথে আপনি যখন প্রক্রিয়াকরণের চেষ্টা করছেন তার আসল বাক্যটি। পাওয়ারশেলকে কল করা নিজেই সমস্যা নয়, আপনি যা করার চেষ্টা করছেন তার মধ্যে। আপনার পোস্টটি সম্পাদনা করুন এবং আপনি কার্যকর করার চেষ্টা করছেন এমন সুস্পষ্ট কল / আদেশগুলি রাখুন।
— ডিআরএপ

1
সত্যিই অদ্ভুত আমি ত্রুটিটি প্রতিলিপি করার চেষ্টা করেছি। এটি 20 টি প্রচেষ্টা বা অন্য কোনও কারণে এলোমেলোভাবে দুবার ঘটেছে এবং আমি এটি আবার ট্রিগার করতে অক্ষম।
— কিকোস

1
@ জোয়েল্টি, ওহ মজাদার, আপনি কি বলছেন যে Rxপদ্ধতিটি কাজ করেছে (যেমন এটি শেষ হয়নি) এমনকি বিপথগামী এমএসবিল্ড প্রক্রিয়াটি অনির্দিষ্ট সময়ের জন্য অপেক্ষা করার জন্য দাঁড়িয়ে আছে? কীভাবে পরিচালনা করা হয়েছিল তা জানতে আগ্রহী
— ক্লিন্ট

উত্তর:


9

আসুন কোনও সম্পর্কিত পোস্টে স্বীকৃত উত্তরের পুনরুদ্ধার দিয়ে শুরু করি ।

সমস্যাটি হ'ল আপনি যদি স্ট্যান্ডার্ডআউটপুট এবং / অথবা স্ট্যান্ডার্ডআরারটিকে পুনর্নির্দেশ করেন তবে অভ্যন্তরীণ বাফারটি পূর্ণ হয়ে উঠতে পারে। আপনি যে কোনও আদেশ ব্যবহার করুন না কেন, সমস্যা হতে পারে:

  • আপনি যদি স্ট্যান্ডার্ডআউটপুট পড়ার আগে প্রক্রিয়াটি প্রস্থান হওয়ার অপেক্ষায় থাকেন তবে প্রক্রিয়াটি এটি লেখার চেষ্টা করতে বাধা দিতে পারে, সুতরাং প্রক্রিয়াটি কখনও শেষ হয় না।
  • আপনি যদি স্ট্যান্ডআউটপুট থেকে রিডটোএন্ড ব্যবহার করে পড়েন তবে প্রক্রিয়াটি স্ট্যান্ডার্ড আউটপুটটি কখনও বন্ধ না করলে আপনার প্রক্রিয়াটি ব্লক করতে পারে (উদাহরণস্বরূপ এটি যদি কখনও অবসান হয় না, বা স্ট্যান্ডার্ডআররে লিখনকে অবরুদ্ধ করা হয়)।

এমনকি গৃহীত উত্তরটি অবশ্য কিছু ক্ষেত্রে মৃত্যুদণ্ডের আদেশের সাথে লড়াই করে।

সম্পাদনা: সময়সীমা শেষ হলে কীভাবে কোনও অবজেক্টডিসপোজড এক্সপেকশন এড়ানো যায় তার জন্য নীচের উত্তরগুলি দেখুন ।

এটি এই ধরণের পরিস্থিতিতে রয়েছে, যেখানে আপনি বেশ কয়েকটি ইভেন্টের অর্কেস্টেট করতে চান, যা আরএক্স সত্যিই জ্বলে।

দ্রষ্টব্য যে Rx .NET প্রয়োগটি সিস্টেম হিসাবে পাওয়া যায় R

আসুন দেখুন কীভাবে আরএক্স ইভেন্টগুলির সাথে কাজ করতে সহায়তা করে।

// Subscribe to OutputData
Observable.FromEventPattern<DataReceivedEventArgs>(process, nameof(Process.OutputDataReceived))
    .Subscribe(
        eventPattern => output.AppendLine(eventPattern.EventArgs.Data),
        exception => error.AppendLine(exception.Message)
    ).DisposeWith(disposables);

FromEventPatternআমাদের একটি সংঘবদ্ধ স্ট্রিমের (ইভেন্ট অব্যারেবল) একটি ইভেন্টের স্বতন্ত্র ঘটনাগুলি ম্যাপ করার অনুমতি দেয়। এটি আমাদের একটি পাইপলাইনে ইভেন্টগুলি পরিচালনা করতে দেয় (লিনকিউ-এর মতো শব্দার্থক সহ)। এখানে Subscribeব্যবহৃত ওভারলোডটি একটি Action<EventPattern<...>>এবং একটি সরবরাহ করা হয় Action<Exception>। যখনই পর্যবেক্ষণ করা ইভেন্টটি উত্থাপিত হয়, এর senderএবং এর argsদ্বারা আবৃত হয়ে EventPatternধাক্কা দেওয়া হবে Action<EventPattern<...>>। পাইপলাইনে একটি ব্যতিক্রম উত্থাপিত হলে, Action<Exception>ব্যবহৃত হয়।

Eventএই ব্যবহারের ক্ষেত্রে পরিষ্কারভাবে চিত্রিত প্যাটার্নের একটি অপূর্ণতা (এবং রেফারেন্সযুক্ত পোস্টের সমস্ত কাজকর্ম দ্বারা) এটি হ'ল ইভেন্ট হ্যান্ডলারদের কখন / কোথায় সাবস্ক্রাইব করবেন তা স্পষ্ট নয়।

আরএক্সের সাহায্যে আমরা IDisposableযখন সাবস্ক্রিপশন করি তখন ফিরে আসি । যখন আমরা এটি নিষ্পত্তি করি তখন আমরা সাবস্ক্রিপশনটি কার্যকরভাবে শেষ করি। করার সাথে সাথে DisposeWithএক্সটেনশন পদ্ধতি (থেকে ধার RxUI ), আমরা একাধিক যোগ করতে পারেন IDisposableএকটি গুলি CompositeDisposable(নামে disposablesকোড নমুনার মধ্যে)। যখন আমরা সব শেষ করে ফেলি, আমরা একটি কল দিয়ে সমস্ত সাবস্ক্রিপশন শেষ করতে পারি disposables.Dispose()।

নিশ্চিত হয়ে বলতে গেলে, আরএক্সের সাথে আমরা কিছুই করতে পারি না, যা আমরা ভ্যানিলা .NET দিয়ে করতে পারব না। একবার আপনি চিন্তার কার্যকরী পদ্ধতিতে অভিযোজিত হয়ে গেলে ফলাফলের কোডটি যুক্তিযুক্ত হতে খুব সহজ।

public static void ExecuteScriptRx(string path, int processTimeOutMilliseconds, out string logs, out bool success, params string[] args)
{
    StringBuilder output = new StringBuilder();
    StringBuilder error = new StringBuilder();

    using (var process = new Process())
    using (var disposables = new CompositeDisposable())
    {
        process.StartInfo = new ProcessStartInfo
        {
            WindowStyle = ProcessWindowStyle.Hidden,
            FileName = "powershell.exe",
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            Arguments = $"-ExecutionPolicy Bypass -File \"{path}\"",
            WorkingDirectory = Path.GetDirectoryName(path)
        };

        if (args.Length > 0)
        {
            var arguments = string.Join(" ", args.Select(x => $"\"{x}\""));
            process.StartInfo.Arguments += $" {arguments}";
        }

        output.AppendLine($"args:'{process.StartInfo.Arguments}'");

        // Raise the Process.Exited event when the process terminates.
        process.EnableRaisingEvents = true;

        // Subscribe to OutputData
        Observable.FromEventPattern<DataReceivedEventArgs>(process, nameof(Process.OutputDataReceived))
            .Subscribe(
                eventPattern => output.AppendLine(eventPattern.EventArgs.Data),
                exception => error.AppendLine(exception.Message)
            ).DisposeWith(disposables);

        // Subscribe to ErrorData
        Observable.FromEventPattern<DataReceivedEventArgs>(process, nameof(Process.ErrorDataReceived))
            .Subscribe(
                eventPattern => error.AppendLine(eventPattern.EventArgs.Data),
                exception => error.AppendLine(exception.Message)
            ).DisposeWith(disposables);

        var processExited =
            // Observable will tick when the process has gracefully exited.
            Observable.FromEventPattern<EventArgs>(process, nameof(Process.Exited))
                // First two lines to tick true when the process has gracefully exited and false when it has timed out.
                .Select(_ => true)
                .Timeout(TimeSpan.FromMilliseconds(processTimeOutMilliseconds), Observable.Return(false))
                // Force termination when the process timed out
                .Do(exitedSuccessfully => { if (!exitedSuccessfully) { try { process.Kill(); } catch {} } } );

        // Subscribe to the Process.Exited event.
        processExited
            .Subscribe()
            .DisposeWith(disposables);

        // Start process(ing)
        process.Start();

        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        // Wait for the process to terminate (gracefully or forced)
        processExited.Take(1).Wait();

        logs = output + Environment.NewLine + error;
        success = process.ExitCode == 0;
    }
}

আমরা ইতিমধ্যে প্রথম অংশটি নিয়ে আলোচনা করেছি, যেখানে আমরা আমাদের ইভেন্টগুলি পর্যবেক্ষণযোগ্যদের কাছে ম্যাপ করি, যাতে আমরা সোজা মাংসের অংশে লাফিয়ে উঠতে পারি। এখানে আমরা আমাদের পর্যবেক্ষণযোগ্যটিকে processExitedভেরিয়েবলের কাছে নিযুক্ত করি, কারণ আমরা এটি একাধিকবার ব্যবহার করতে চাই।

প্রথমত, যখন আমরা এটি সক্রিয় করি তখন কল করে Subscribe। এবং পরে যখন আমরা এর প্রথম মানটি 'অপেক্ষা' করতে চাই want

var processExited =
    // Observable will tick when the process has gracefully exited.
    Observable.FromEventPattern<EventArgs>(process, nameof(Process.Exited))
        // First two lines to tick true when the process has gracefully exited and false when it has timed out.
        .Select(_ => true)
        .Timeout(TimeSpan.FromMilliseconds(processTimeOutMilliseconds), Observable.Return(false))
        // Force termination when the process timed out
        .Do(exitedSuccessfully => { if (!exitedSuccessfully) { try { process.Kill(); } catch {} } } );

// Subscribe to the Process.Exited event.
processExited
    .Subscribe()
    .DisposeWith(disposables);

// Start process(ing)
...

// Wait for the process to terminate (gracefully or forced)
processExited.Take(1).Wait();

ওপিতে সমস্যাগুলির মধ্যে একটি হ'ল এটি ধরে নিয়েছে যে সময় process.WaitForExit(processTimeOutMiliseconds)শেষ হয়ে গেলে প্রক্রিয়াটি শেষ করে দেবে। এমএসডিএন থেকে :

সম্পর্কিত প্রক্রিয়াটি প্রস্থান করার জন্য মিলিসেকেন্ডের নির্দিষ্ট সংখ্যার জন্য অপেক্ষা করতে প্রক্রিয়া উপাদানটিকে নির্দেশ দেয় ucts

পরিবর্তে, যখন এটি শেষ হয়ে যায় তখন এটি কেবল বর্তমান থ্রেডে নিয়ন্ত্রণ ফিরিয়ে দেয় (যেমন এটি ব্লক করা বন্ধ করে)। প্রক্রিয়াটি শেষ হয়ে গেলে আপনাকে ম্যানুয়ালি সমাপ্তি জোর করতে হবে। যখন জানতে সময় বের ঘটেছে, আমরা ম্যাপ করতে পারেন Process.Exitedএকটি ইভেন্টের processExitedপ্রক্রিয়াকরণের জন্য পর্যবেক্ষণযোগ্য। এইভাবে আমরা Doঅপারেটরের জন্য ইনপুট প্রস্তুত করতে পারি ।

কোডটি বেশ স্ব-বর্ণনামূলক। যদি exitedSuccessfullyপ্রক্রিয়াটি করুণভাবে শেষ হয়ে যায়। যদি তা না হয় তবে exitedSuccessfullyসমাপ্তি বাধ্য করতে হবে। নোট যে process.Kill()অ্যাসিঙ্ক্রোনালি কার্যকর করা হয়, রেফারেন্স মন্তব্য । তবে process.WaitForExit()ঠিক পরেই কল করা আবার অচলাবস্থার সম্ভাবনা খুলে দেবে। এমনকি জোরপূর্বক সমাপ্তির ক্ষেত্রেও, usingসুযোগটি শেষ হয়ে গেলে সমস্ত ডিসপোজেবলগুলি পরিষ্কার করা ভাল , কারণ আউটপুট যে কোনওভাবে বাধা / দুর্নীতি হিসাবে বিবেচনা করা যেতে পারে।

try catchকনস্ট্রাক্ট ব্যতিক্রমী ক্ষেত্রে (কোনো শ্লেষ উদ্দেশ্যে) যেখানে আপনি প্রান্তিককৃত থাকেন জন্য সংরক্ষিত processTimeOutMillisecondsসম্পূর্ণ প্রক্রিয়া প্রয়োজনীয় প্রকৃত সময় সঙ্গে। অন্য কথায়, Process.Exitedইভেন্ট এবং টাইমার মধ্যে একটি দৌড়ের অবস্থা দেখা দেয়। এর অ্যাসিনক্রোনাস প্রকৃতির দ্বারা এই ঘটনার সম্ভাবনা আবার বাড়ানো হয়েছে process.Kill()। পরীক্ষার সময় আমি একবার এর মুখোমুখি হয়েছি।


সম্পূর্ণতার জন্য, DisposeWithএক্সটেনশন পদ্ধতি।

/// <summary>
/// Extension methods associated with the IDisposable interface.
/// </summary>
public static class DisposableExtensions
{
    /// <summary>
    /// Ensures the provided disposable is disposed with the specified <see cref="CompositeDisposable"/>.
    /// </summary>
    public static T DisposeWith<T>(this T item, CompositeDisposable compositeDisposable)
        where T : IDisposable
    {
        if (compositeDisposable == null)
        {
            throw new ArgumentNullException(nameof(compositeDisposable));
        }

        compositeDisposable.Add(item);
        return item;
    }
}

4
আইএমএইচও, অবশ্যই অনুগ্রহের মূল্যবান। উত্তম উত্তর, এবং আরএক্স-এ দুর্দান্ত বিষয় সম্পর্কিত পরিচয়।
— কোয়েটজলকোটল

ধন্যবাদ !!! আপনার ExecuteScriptRxহাতল hangsপুরোপুরি। Unfortunely হ্যাং এখনও ঘটতে, কিন্তু আমি শুধু আপনার উপর ছোট মোড়কের যোগ ExecuteScriptRxযে সঞ্চালিত Retryএবং তারপর এটা জরিমানা সঞ্চালন করে। এমএসবিল্ড হ্যাং হওয়ার কারণটি @ ক্লিন্টের উত্তর হতে পারে। পিএস: এই কোডটি আমাকে বোকা মনে করেছে System.Reactive.Linq;
— << লল


3

জন্য সুবিধা পাঠকদের আমি 2 সেকশনস এই বিভক্ত করতে যাচ্ছি

বিভাগ অ: সমস্যা এবং কীভাবে অনুরূপ পরিস্থিতি পরিচালনা করবেন

বিভাগ বি: সমস্যা বিনোদন এবং সমাধান

বিভাগ অ: সমস্যা

যখন এই সমস্যাটি ঘটে - প্রক্রিয়াটি টাস্ক ম্যানেজারে উপস্থিত হয়, তারপরে ২-৩ সেকেন্ড অদৃশ্য হয়ে যাওয়ার পরে (এর সূক্ষ্ম) হয়ে যায়, তারপরে এটি সময়সীমার জন্য অপেক্ষা করে এবং তারপরে ব্যতিক্রমটি ছুঁড়ে ফেলা হয়।

& নীচে পরিস্থিতি 4 দেখুন

আপনার কোডে:

  1. Process.WaitForExit(ProcessTimeOutMiliseconds); এটির সাহায্যেProcess আপনি টাইমআউট বা প্রস্থান করার অপেক্ষায় রয়েছেন যা কখনই প্রথম হয় ।
  2. OutputWaitHandle.WaitOne(ProcessTimeOutMiliseconds)এবং এটির সাথে আপনি এর সম্পূর্ণ ইঙ্গিত দেওয়ার errorWaitHandle.WaitOne(ProcessTimeOutMiliseconds); জন্য OutputData& ErrorDataস্ট্রিম রিড অপারেশনের জন্য অপেক্ষা করছেন
  3. Process.ExitCode == 0 প্রক্রিয়াটি যখন বের হয় তখন স্থিতি পায়

বিভিন্ন সেটিংস এবং তাদের সতর্কতা:

  • পরিস্থিতি 1 (শুভ পথ) : প্রক্রিয়াটি সময়সীমা শেষ হওয়ার আগেই শেষ হয়ে যায় এবং এভাবে আপনার স্টডআউটপুট এবং স্টারডরও এর আগে শেষ হয় এবং সবকিছু ঠিকঠাক হয়।
  • দৃশ্য 2 : প্রক্রিয়া, আউটপুটওয়েটহ্যান্ডেল এবং ত্রুটিবাহিত হ্যান্ডল টাইমআউট তবে স্টড আউটপুট এবং স্ট্ডারআর এখনও পড়া হচ্ছে এবং ওয়েটহ্যান্ডলারের সময় শেষ হওয়ার পরে সম্পূর্ণ হয়। এটি অন্য ব্যতিক্রম বাড়েObjectDisposedException()
  • পরিস্থিতি 3 : প্রসেস টাইম-আউট প্রথম (19 সেকেন্ড) তবে স্টাডআউট এবং স্টারডোর ক্রিয়াকলাপে রয়েছে, আপনি ওয়েটহ্যান্ডলারের টাইম আউট (১৯ সেকেন্ড) এর জন্য অপেক্ষা করুন, এতে + 19 সেকেন্ডের অতিরিক্ত বিলম্ব ঘটে।
  • পরিস্থিতি 4 : প্রক্রিয়া সময় শেষ হয়ে যায় এবং কোড অকালপূর্বে জিজ্ঞাসা করার চেষ্টা Process.ExitCodeকরে ত্রুটির ফলে System.InvalidOperationException: Process must exit before requested information can be determined।

আমি এই দৃশ্যটি এক ডজনেরও বেশি বার পরীক্ষা করেছি এবং ভাল কাজ করেছি, পরীক্ষার সময় নিম্নলিখিত সেটিংস ব্যবহার করা হয়েছে

  • প্রায় 2-15 প্রকল্পের নির্মাণ শুরু করে 5KB থেকে 198KB অবধি আউটপুট স্ট্রিমের আকার
  • অসময়ের সময়সীমা এবং প্রক্রিয়া টাইমআউট উইন্ডোর মধ্যে প্রস্থান করে


আপডেট কোড

.
.
.
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();

    //First waiting for ReadOperations to Timeout and then check Process to Timeout
    if (!outputWaitHandle.WaitOne(ProcessTimeOutMiliseconds) && !errorWaitHandle.WaitOne(ProcessTimeOutMiliseconds)
        && !process.WaitForExit(ProcessTimeOutMiliseconds)  )
    {
        //To cancel the Read operation if the process is stil reading after the timeout this will prevent ObjectDisposeException
        process.CancelOutputRead();
        process.CancelErrorRead();

        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("Timed Out");
        Logs = output + Environment.NewLine + error;
       //To release allocated resource for the Process
        process.Close();
        return  (false, logs);
    }

    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine("Completed On Time");
    Logs = output + Environment.NewLine + error;
    ExitCode = process.ExitCode.ToString();
    // Close frees the memory allocated to the exited process
    process.Close();

    //ExitCode now accessible
    return process.ExitCode == 0 ? (true, logs) : (false, logs);
    }
}
finally{}

সম্পাদনা করুন:

এমএসবিল্ডের সাথে ঘণ্টার পর ঘণ্টা খেলার পরে আমি শেষ পর্যন্ত আমার সিস্টেমে সমস্যাটি পুনরুত্পাদন করতে সক্ষম হয়েছি


বিভাগ বি: সমস্যা বিনোদন এবং সমাধান

MSBuild হয়েছে-m[:number]সুইচ যা বিল্ডিং ব্যবহারের জন্য সংঘটনশীল প্রসেস সর্বোচ্চ সংখ্যক নির্দিষ্ট করতে ব্যবহার করা হয়।

এটি সক্ষম করা হলে, এমএসবাইল্ড বিল্ড সম্পূর্ণ হওয়ার পরেও বেঁচে থাকা বেশ কয়েকটি নোডকে স্প্যান করে। এখন, Process.WaitForExit(milliseconds)কখনই বাহির না হওয়া এবং শেষ অবধি অপেক্ষা করতে হবে

আমি কয়েকটা উপায়ে এটি সমাধান করতে সক্ষম হয়েছি

  • স্পেন এমএসবিল্ড প্রক্রিয়াটি পরোক্ষভাবে সিএমডি এর মাধ্যমে

    $path1 = """C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe"" ""C:\Users\John\source\repos\Test\Test.sln"" -maxcpucount:3"
    $cmdOutput = cmd.exe /c $path1  '2>&1'
    $cmdOutput
  • এমএসবিল্ড ব্যবহার চালিয়ে যান তবে নোডরাইজকে মিথ্যাতে সেট করতে ভুলবেন না

    $filepath = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe"
    $arg1 = "C:\Users\John\source\repos\Test\Test.sln"
    $arg2 = "-m:3"
    $arg3 = "-nr:False"
    
    Start-Process -FilePath $filepath -ArgumentList $arg1,$arg2,$arg3 -Wait -NoNewWindow
  • সমান্তরাল বিল্ড সক্ষম না করা সত্ত্বেও, আপনি সিএমডি এরWaitForExit মাধ্যমে বিল্ড চালু করে আপনার প্রক্রিয়াটি ঝুলানো থেকে আটকাতে পারেন এবং তাই আপনি বিল্ড প্রক্রিয়াতে সরাসরি নির্ভরতা তৈরি করেন না

    $path1 = """C:\....\15.0\Bin\MSBuild.exe"" ""C:\Users\John\source\Test.sln"""
    $cmdOutput = cmd.exe /c $path1  '2>&1'
    $cmdOutput

আপনি যদি এমএসবিল্ডের অনেক বেশি নোডের আশেপাশে পড়ে থাকতে চান না তবে ২ য় পন্থা পছন্দ করা হয়।


সুতরাং, যেমন আমি উপরে বলেছি, ধন্যবাদ, এটি "-nr:False","-m:3"এমএসবিল্ড হ্যাং-ইশ আচরণটি স্থির করে দিয়েছে যা Rx solutionপুরো প্রক্রিয়াটি কিছুটা নির্ভরযোগ্য করে তুলেছে (সময়ের শো) show আমি আশা করি আমি উভয় উত্তর গ্রহণ করতে বা দুটি
— উপার্জন

@ জয়েলি আমি কেবল Rxঅন্য সমাধানে পদ্ধতির প্রয়োগ না করে সমস্যা সমাধান করতে সক্ষম কিনা তা জানার চেষ্টা করছিলাম-nr:False" ,"-m:3" । আমার বোঝার মধ্যে এটি অধ্যায় 1 এবং আমি যে বিভাগটি 1 এ আচ্ছাদিত করেছি সেগুলি থেকে অনির্দিষ্টকালের জন্য অপেক্ষা করা হয় Section এবং বিভাগ 2 এর মূল কারণটি হ'ল আমি বিশ্বাস করি যে আপনি যে সমস্যার মুখোমুখি হয়েছিলেন তার মূল কারণ;) আমি ভুল হতে পারি যার কারণেই জিজ্ঞাসা করলাম, কেবল সময়ই বলবে ... চিয়ার্স !!
— ক্লিন্ট

3

সমস্যাটি হ'ল আপনি যদি স্ট্যান্ডার্ডআউটপুট এবং / অথবা স্ট্যান্ডার্ডআরারটিকে পুনর্নির্দেশ করেন তবে অভ্যন্তরীণ বাফারটি পূর্ণ হয়ে উঠতে পারে।

পূর্বোক্ত সমস্যাগুলি সমাধান করতে আপনি পৃথক থ্রেডে প্রক্রিয়াটি চালাতে পারেন। আমি ওয়েটফরএক্সিট ব্যবহার করি না, আমি প্রক্রিয়াটি প্রস্থানিত ইভেন্টটি ব্যবহার করি যা প্রক্রিয়াটির এক্সিটকোডকে সংশ্লেষপূর্বকভাবে সম্পন্ন করে নিশ্চিত করবে return

public async Task<int> RunProcessAsync(params string[] args)
    {
        try
        {
            var tcs = new TaskCompletionSource<int>();

            var process = new Process
            {
                StartInfo = {
                    FileName = 'file path',
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    Arguments = "shell command",
                    UseShellExecute = false,
                    CreateNoWindow = true
                },
                EnableRaisingEvents = true
            };


            process.Exited += (sender, args) =>
            {
                tcs.SetResult(process.ExitCode);
                process.Dispose();
            };

            process.Start();
            // Use asynchronous read operations on at least one of the streams.
            // Reading both streams synchronously would generate another deadlock.
            process.BeginOutputReadLine();
            string tmpErrorOut = await process.StandardError.ReadToEndAsync();
            //process.WaitForExit();


            return await tcs.Task;
        }
        catch (Exception ee) {
            Console.WriteLine(ee.Message);
        }
        return -1;
    }

উপরের কোডটি যুদ্ধের পরীক্ষা করা FFMPEG.exe কমান্ড লাইন আর্গুমেন্টের সাথে কল করা। আমি এমপি 4 ফাইলগুলিকে এমপি 3 ফাইলে রূপান্তর করছিলাম এবং একবারে ব্যর্থ না হয়ে 1000 এরও বেশি ভিডিও করছিলাম। দুর্ভাগ্যক্রমে আমার কাছে সরাসরি পাওয়ার শেল অভিজ্ঞতা নেই তবে আশা করি এটি সাহায্য করবে।


এই কোডটি অদ্ভুত, অন্য সমাধানগুলির মতো একইভাবে প্রথম প্রচেষ্টা ব্যর্থ (আটকে) এবং তারপরে সূক্ষ্মভাবে কাজ করার মতো মনে হয়েছিল (অন্যান্য 5 টি প্রচেষ্টার মতো, আমি এটি আরও পরীক্ষা করব)। BTW কেন সঞ্চালন না BegingOutputReadlineএবং তারপর সঞ্চালন ReadToEndAsyncউপর StandardError?
— জোয়েল্টি

ওপি ইতিমধ্যে অবিচ্ছিন্নভাবে পড়ছে, সুতরাং কনসোল বাফারের একটি অচলাবস্থার বিষয়টি এখানেই আসার সম্ভাবনা নেই।
— ইয়াকভ

0

এটি আপনার সমস্যা কিনা তা নিশ্চিত না, তবে এমএসডিএনকে দেখে বোঝা যাচ্ছে যে আপনি যখন অ্যাসিঙ্ক্রোনালি আউটপুটটি পুনঃনির্দেশ করছেন তখন অতিরিক্ত লোড ওয়েটফরেক্সটটির সাথে কিছুটা অদ্ভুততা রয়েছে। এমএসডিএন নিবন্ধটি ওয়েটফোরএক্সিটকে কল করার পরামর্শ দেয় যা অতিরিক্ত লোড পদ্ধতিটি কল করার পরে কোনও যুক্তি নেয় না।

ডক্স পৃষ্ঠা এখানে অবস্থিত ।প্রাসঙ্গিক পাঠ্য:

যখন স্ট্যান্ডার্ড আউটপুট অ্যাসিক্রোনাস ইভেন্ট হ্যান্ডলারগুলিতে পুনঃনির্দেশিত করা হয় তখন সম্ভব হয় যে এই পদ্ধতিটি ফিরে আসার পরে আউটপুট প্রক্রিয়াকরণ সম্পন্ন হবে না। অ্যাসিঙ্ক্রোনাস ইভেন্ট হ্যান্ডলিং সম্পন্ন হয়েছে তা নিশ্চিত করার জন্য, এই ওভারলোড থেকে সত্য পাওয়ার পরে কোনও পরামিতি নেয় না এমন ওয়েটফরেক্সট () ওভারলোডকে কল করুন। প্রস্থানিত ইভেন্টটি উইন্ডোজ ফর্ম অ্যাপ্লিকেশনগুলিতে সঠিকভাবে পরিচালিত হয়েছে তা নিশ্চিত করতে সহায়তা করতে সিঙ্ক্রোনাইজিংঅবজেক্ট সম্পত্তি সেট করুন।

কোড পরিবর্তন এই জাতীয় কিছু দেখতে পারে:

if (process.WaitForExit(ProcessTimeOutMiliseconds))
{
  process.WaitForExit();
}

এই উত্তরেরprocess.WaitForExit() মন্তব্যে নির্দেশিত হিসাবে ব্যবহারের সাথে কিছু জটিলতা রয়েছে ।
— in
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.