"대기 가능한"메서드를 작성하는 방법은 무엇입니까?
나는 마지막으로 예를 들면 종류의 "수"의 I,하지만 모든 예제 내가 닷넷 프레임 워크의 방법 비동기 호출을 본 적이 비동기 및 await를 키워드로 찾고 있어요 이 하나의 호출 HttpClient.GetStringAsync()
.
내가 그다지 명확하지 않은 것은 그러한 방법에서 무슨 일이 일어나는지, 그리고 내가 "기다릴 수있는"방법을 어떻게 작성하는지에 관한 것이다. Task에서 비동기 적으로 실행하려는 코드를 래핑하고 반환하는 것만 큼 간단합니까?
간단합니다.
Task.Run(() => ExpensiveTask());
대기 가능한 메서드로 만들려면 :
public Task ExpensiveTaskAsync()
{
return Task.Run(() => ExpensiveTask());
}
여기서 중요한 것은 작업을 반환하는 것입니다. 메서드는 비동기로 표시 할 필요조차 없습니다. (사진에 나오려면 조금 더 읽으십시오)
이제 이것은 다음과 같이 부를 수 있습니다.
async public void DoStuff()
{
PrepareExpensiveTask();
await ExpensiveTaskAsync();
UseResultsOfExpensiveTask();
}
async
메서드가 반환 될 때까지 호출자에게 제어를 반환 할 수 있기 때문에 여기에서 메서드 서명이이라고 말합니다 ExpensiveTaskAsync()
. 또한이 경우 비용이 많이 들기 때문에 웹 요청과 같이 시간이 많이 걸립니다. 무거운 계산을 다른 스레드로 보내려면 일반적으로 "이전"접근 방식을 사용하는 것이 좋습니다 (예 System.ComponentModel.BackgroundWorker
: GUI 응용 프로그램 또는 System.Threading.Thread
.
내 자신의 "대기 가능한"메서드를 어떻게 작성합니까? 비동기 적으로 실행하려는 코드를 a에서 래핑
Task
하고 반환하는 것만 큼 간단 합니까?
이것은 하나의 옵션이지만 실제로 비동기 코드의 많은 이점을 제공하지 않기 때문에 원하는 작업이 아닐 가능성이 큽니다. 자세한 내용은 Stephen Toub의 동기 메서드에 대한 비동기 래퍼를 노출해야합니까?를 참조하십시오 .
일반적으로 메소드는 기다릴 수 없으며 유형 은 있습니다. 당신이 뭔가를 쓸 수 있도록하려면 await MyMethod()
, 다음 MyMethod()
반환하는 Task
, Task<T>
또는 사용자 정의 await
할 수 유형입니다. 사용자 정의 유형을 사용하는 것은 드문 고급 시나리오입니다. 를 사용 Task
하면 몇 가지 옵션이 있습니다.
async
및을 사용하여 방법을 작성하십시오await
. 이것은 비동기 적으로 작업 을 작성하는 데 유용 하지만 가장 안쪽의await
가능한 호출 에는 사용할 수 없습니다 .- , like 또는
Task
에 대한 방법 중 하나를 사용 하여을 만듭니다 .Task
Task.Run()
Task.FromAsync()
- 사용
TaskCompletionSource
. 이것은 가장 일반적인 접근 방식이며await
미래에 일어날 모든 것에서 가능한 방법 을 만드는 데 사용할 수 있습니다 .
... 내 자신의 "기다릴 수있는"방법을 작성하는 방법.
a를 반환하는 Task
것이 유일한 방법은 아닙니다. 사용자 지정 대기자 를 생성 할 수있는 옵션이 있습니다 ( 및를 구현 GetAwaiter
하여 INotifyCompletion
). 여기에 훌륭한 읽기 : " Await any "가 있습니다. 사용자 지정 대기자를 반환하는 .NET API의 예 : Task.Yield()
, Dispatcher.InvokeAsync
.
여기 와 여기에 사용자 지정 대기자가있는 게시물이 있습니다 . 예 :
// don't use this in production
public static class SwitchContext
{
public static Awaiter Yield() { return new Awaiter(); }
public struct Awaiter : System.Runtime.CompilerServices.INotifyCompletion
{
public Awaiter GetAwaiter() { return this; }
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem((state) => ((Action)state)(), continuation);
}
public void GetResult() { }
}
}
// ...
await SwitchContext.Yield();
예, 기술적으로 당신은 단지를 반환해야 Task
또는 Task<Result>
에서 async
awaitable 방법을 구현하는 방법.
이것은 Task-Based Asynchronous Pattern을 지원합니다 .
그러나 TAP를 구현하는 방법에는 여러 가지가 있습니다. 자세한 내용 은 작업 기반 비동기 패턴 구현 을 참조하세요.
(그러나이 모든 구현은 여전히 반환 Task
또는 Task<Result>
물론.)
방법을 Task로 변환하십시오. @Romiox처럼 나는 일반적 으로이 확장자를 사용합니다.
public static partial class Ext
{
#region Public Methods
public static Task ToTask(Action action)
{
return Task.Run(action);
}
public static Task<T> ToTask<T>(Func<T> function)
{
return Task.Run(function);
}
public static async Task ToTaskAsync(Action action)
{
await Task.Run(action);
}
public static async Task<T> ToTaskAsync<T>(Func<T> function)
{
return await Task.Run(function);
}
#endregion Public Methods
}
이제 우리는 당신이
무효 foo1 ()
무효 foo2 (int i1)
int foo3 ()
int foo4 (int i1)
... 그런 다음 @Romiox와 같은 [비동기 메서드]를 선언 할 수 있습니다.
async Task foo1Async(){
return await Ext.ToTask(()=>foo1());
}
async Task foo2Async(int i1){
return await Ext.ToTask(()=>foo2(i1));
}
async Task<int> foo3Async(){
return await Ext.ToTask(()=>foo3());
}
async Task<int> foo4Async(int i1){
return await Ext.ToTask(()=>foo4(i1));
}
또는
async Task foo1Async(){
return await Ext.ToTaskAsync(()=>foo1());
}
async Task foo2Async(int i1){
return await Ext.ToTaskAsync(()=>foo2(i1));
}
async Task<int> foo3Async(){
return await Ext.ToTaskAsync(()=>foo3());
}
async Task<int> foo4Async(int i1){
return await Ext.ToTaskAsync(()=>foo4(i1));
}
...
이제 async를 사용하고 fooAsync 예를 들어 foo4Async를 기다립니다.
async Task<int> TestAsync()
{
///Initial Code
int m=3;
///Call the task
var X =foo4Async(m);
///Between
///Do something while waiting comes here
///..
var Result =await X;
///Final
///Some Code here
return Result;
}
를 사용하지 않으려면 Task
완전히 사용자 정의 된 awaitable 객체를 작성할 수 있습니다. 이러한 객체는 객체 자체가 될 수 GetAwaiter ()
있는를 구현하는 객체를 반환하는 메서드를 구현하는 INotifyCompletion
것입니다.
더보기 : INotifyCompletion
awaiter는 다음을 구현합니다.
IsCompleted
상태를 얻는 것입니다GetResult ()
결과를 얻기 위해OnCompleted (Action continuation)
연속 대리자를 설정합니다.
The awaitable object contains some method for actual payload (e.g. below, the method is Run
).
class Program {
// Need to change the declaration of Main() in order to use 'await'
static async Task Main () {
// Create a custom awaitable object
MyAwaitable awaitable = new MyAwaitable ();
// Run awaitable payload, ignore returned Task
_ = awaitable.Run ();
// Do some other tasks while awaitable is running
Console.WriteLine ("Waiting for completion...");
// Wait for completion
await awaitable;
Console.WriteLine ("The long operation is now complete. " + awaitable.GetResult());
}
}
public class MyAwaitable : INotifyCompletion {
// Fields
private Action continuation = null;
private string result = string.Empty;
// Make this class awaitable
public MyAwaitable GetAwaiter () { return this; }
// Implementation of INotifyCompletion for the self-awaiter
public bool IsCompleted { get; set; }
public string GetResult () { return result; }
public void OnCompleted (Action continuation) {
// Store continuation delegate
this.continuation = continuation;
Console.WriteLine ("Continuation set");
}
// Payload to run
public async Task Run () {
Console.WriteLine ("Computing result...");
// Wait 2 seconds
await Task.Delay (2000);
result = "The result is 10";
// Set completed
IsCompleted = true;
Console.WriteLine ("Result available");
// Continue with the continuation provided
continuation?.Invoke ();
}
}
참고URL : https://stackoverflow.com/questions/21700846/how-to-write-an-awaitable-method
'code' 카테고리의 다른 글
for..in 및 hasOwnProperty (0) | 2020.12.01 |
---|---|
JavaScript setInterval () 메서드로 인해 메모리 누수가 발생합니까? (0) | 2020.12.01 |
Pandas DataFrame 성능 (0) | 2020.12.01 |
Spring 데이터 jpa- 'entityManagerFactory'라는 이름의 빈이 정의되지 않았습니다. (0) | 2020.12.01 |
축은 numpy의 배열에서 어떻게 인덱싱됩니까? (0) | 2020.11.30 |