/// <summary> /// Writes job output objects and propagates streams. /// Moves refilling objects from output to the queue. /// </summary> /// <remarks> /// v1.4.2 Only errors are propagated, other streams are written to the host. /// </remarks> void WriteResults(Job job, ICollection<PSObject> output) { // process output if (output != null && output.Count > 0) { if (Refill) { foreach (var it in output) { if (it != null) { var reference = it.BaseObject as PSReference; if (reference == null) WriteObject(it); else Enqueue(new PSObject(reference.Value)); } } } else { foreach (var it in output) WriteObject(it); } } // process streams var streams = job.Streams; // v1.4.2 Even with the shared host errors must be propagated explicitly. if (streams.Error.Count > 0) { foreach (var record in streams.Error) WriteError(record); } // v1.4.2 Debug, progress, verbose, and warning messages are written to the host. // But streams are still populated, so we clear them on writing results. // NB: It is possible to log these streams in addition. streams.ClearStreams(); }
/// <summary> /// Gets the next part of input items and feeds them to a ready job. /// If forced waits for a ready job. /// </summary> void Feed(bool force) { // try to make more jobs ready and more input available on Refill Take(); // no input? check this after taking, Refill adds input on taking if (_queue.Count == 0) return; // all busy? if (_Count - _work.Count == 0) { // no ready jobs, done if not forced if (!force) return; // wait for jobs and make them ready Wait(); Take(); } // split the queue equally between all potential jobs int load = _queue.Count / _Count; if (load * _Count < _queue.Count) ++load; // check limits if (load < MinLoad) load = MinLoad; else if (load > MaxLoad) load = MaxLoad; lock (_syncObject) { int nReadyJobs = _Count - _work.Count; if (xStop || nReadyJobs == 0) return; do { // limit load by the queue if (load > _queue.Count) { load = _queue.Count; // if load is less than minimum and not forced then exit if (load < MinLoad && !force) return; } // next job node LinkedListNode<Job> node = _done.First; if (node == null) { // v1.4.2 Runspaces use the same host as the cmdlet. var job = new Job(RunspaceFactory.CreateRunspace(Host, _iss)); node = new LinkedListNode<Job>(job); _work.AddLast(node); WriteResults(job, job.InvokeBegin(_Begin, _Script)); } else { _done.RemoveFirst(); _work.AddLast(node); } if (xStop) return; // feed the job ++_infoPartCount; node.Value.BeginInvoke(_queue, load); // show feed info if (_verbose) WriteVerbose(string.Format(null, "Split-Pipeline: Jobs = {0}; Load = {1}; Queue = {2}", _work.Count, load, _queue.Count)); } while (!xStop && --nReadyJobs > 0 && _queue.Count > 0); } }