PowerShell에서 비동기 C# 메서드 대기
다음과 같은 정적 멤버 액세스 장치를 사용하여 PowerShell에서 정적 비동기 C# 메서드를 호출하려고 합니다.
파워셸
function CallMyStaticMethod([parameter(Mandatory=$true)][string]$myParam)
{
...
[MyNamespace.MyClass]::MyStaticMethod($myParam)
...
}
C#
public static async Task MyStaticMethod(string myParam)
{
...
await ...
...
}
내 C# 메서드는 비동기식이므로 PowerShell에서 일종의 "대기" 호출 없이 C# 메서드가 제대로 실행될 수 있습니까?
자체적으로 잘 실행되지만 완료될 때까지 기다리려면 이 기능을 사용할 수 있습니다.
$null = [MyNamespace.MyClass]::MyStaticMethod($myParam).GetAwaiter().GetResult()
이렇게 하면 포장이 풀립니다.AggregateException
만약 당신이 같은 것을 사용한다면 그것은 던져질 것입니다.$task.Result
대신.
하지만 그것은 완성될 때까지 차단될 것이고, 그것은 그것을 막을 것입니다.CTRL + C
파이프라인이 제대로 정지되지 않습니다.파이프라인 중지를 준수하는 동안 이 작업이 완료될 때까지 기다릴 수 있습니다.
$task = [MyNamespace.MyClass]::MyStaticMethod($myParam)
while (-not $task.AsyncWaitHandle.WaitOne(200)) { }
$null = $task.GetAwaiter().GetResult()
비동기 메서드가 실제로 무언가를 반환하는 경우 제거$null =
패트릭 마인케의 대답을 빌려, 당신을 위해 작업(또는 작업 목록)을 해결해 줄 파이프라인이 가능한 기능을 만들 수 있습니다.
function Await-Task {
param (
[Parameter(ValueFromPipeline=$true, Mandatory=$true)]
$task
)
process {
while (-not $task.AsyncWaitHandle.WaitOne(200)) { }
$task.GetAwaiter().GetResult()
}
}
용도:
$results = Get-SomeTasks $paramA $paramB | Await-Task
최근에 우연히 이 문제를 발견했는데 PowerShell 작업을 생성하는 것도 꽤 효과적인 방법인 것 같습니다.이렇게 하면 표준 작업 기능(대기-작업, 수신-작업 및 제거)이 제공됩니다.일은 힘들 수 있지만, 이것은 꽤 간단합니다.C#으로 작성되었으므로 Add-Type을 사용하여 추가하거나 컴파일해야 할 수 있습니다(작성 방법을 수정해야 합니다. Add-TypeDefinition '...'은 lamdas를 사용할 때 실패하는 것 같습니다. 따라서 적절한 Get accessor로 대체해야 합니다.).
using System;
using System.Management.Automation;
using System.Threading;
using System.Threading.Tasks;
namespace MyNamespace
{
public class TaskJob : Job
{
private readonly Task _task;
private readonly CancellationTokenSource? _cts;
public override bool HasMoreData => Error.Count > 0 || Output.Count > 0;
public sealed override string Location => Environment.MachineName;
public override string StatusMessage => _task.Status.ToString();
public override void StopJob()
{
// to prevent the job from hanging, we'll say the job is stopped
// if we can't stop it. Otherwise, we'll cancel _cts and let the
// .ContinueWith() invocation set the job's state.
if (_cts is null)
{
SetJobState(JobState.Stopped);
}
else
{
_cts.Cancel();
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_task.Dispose();
_cts?.Dispose();
}
base.Dispose(disposing);
}
public TaskJob(string? name, string? command, Task task, CancellationTokenSource? cancellationTokenSource)
: base(command, name)
{
PSJobTypeName = nameof(TaskJob);
if (task is null)
{
throw new ArgumentNullException(nameof(task));
}
_task = task;
task.ContinueWith(OnTaskCompleted);
_cts = cancellationTokenSource;
}
public virtual void OnTaskCompleted(Task task)
{
if (task.IsCanceled)
{
SetJobState(JobState.Stopped);
}
else if (task.Exception != null)
{
Error.Add(new ErrorRecord(
task.Exception,
"TaskException",
ErrorCategory.NotSpecified,
task)
{
ErrorDetails = new ErrorDetails($"An exception occurred in the task. {task.Exception}"),
}
);
SetJobState(JobState.Failed);
}
else
{
SetJobState(JobState.Completed);
}
}
}
public class TaskJob<T> : TaskJob
{
public TaskJob(string? name, string? command, Task<T> task, CancellationTokenSource? cancellationTokenSource)
: base(name, command, task, cancellationTokenSource)
{
}
public override void OnTaskCompleted(Task task)
{
if (task is Task<T> taskT)
{
try
{
Output.Add(PSObject.AsPSObject(taskT.GetAwaiter().GetResult()));
}
// error handling dealt with in base.OnTaskCompleted
catch { }
}
base.OnTaskCompleted(task);
}
}
}
PowerShell 세션에 이 클래스를 추가한 후에는 태스크를 태스크로 쉽게 전환할 수 있습니다.
$task = [MyNamespace.MyClass]::MyStaticMethod($myParam)
$job = ([MyNamespace.TaskJob]::new('MyTaskJob', $MyInvocation.Line, $task, $null))
# Add the job to the repository so that it can be retrieved later. This requires that you're using an advanced script or function (has an attribute declaration, particularly [CmldetBinding()] before the param() block). If not, you can always make a Register-Job function to just take an unregistered job and add it to the job repository.
$PSCmdlet.JobRepository.Add($job)
# now you can do all this with your task
Get-Job 'MyTaskJob' | Wait-Job
Get-Job 'MyTaskJob' | Receive-Job
Get-Job 'MyTaskJob' | Remove-Job
저는 제가 업무에 대해 매우 익숙하지 않다는 것을 지적할 것입니다. 그래서 누군가 위에서 나쁘게 보이는 것을 본다면, 저는 항상 개선할 방법을 찾고 있습니다.:)
보다 발전된 개념은 이 작업 작업 안내서에서 확인할 수 있습니다.
언급URL : https://stackoverflow.com/questions/51218257/await-async-c-sharp-method-from-powershell
'UFO ET IT' 카테고리의 다른 글
main 끝에 있는 return 0을 선택적으로 만든 이유는? (0) | 2023.08.21 |
---|---|
jQuery 셀렉터에서 DOM 요소를 가져오는 방법은 무엇입니까? (0) | 2023.08.21 |
wordpress 테마, 플뤼그 등에 의해 저장된 기본 인코딩 문자열 내부의 localhost URL 대체 (0) | 2023.06.22 |
Vuex 작업에서 여러 커밋을 테스트하는 방법 (0) | 2023.06.22 |
Spring Boot 애플리케이션을 클래스 경로로 시작하지 못했습니다. [] (0) | 2023.06.22 |