일부 비동기 기능이있는 인터페이스가 있습니다. 인터페이스를 구현하는 일부 클래스는 기다릴 것이 없으며 일부는 그냥 던질 수 있습니다. 모든 경고로 인해 약간 짜증이납니다.
비동기 함수에서 await를 사용하지 않을 때.
메시지를 숨길 수 있습니까?
public async Task<object> test()
{
throw new NotImplementedException();
}
경고 CS1998 :이 비동기 메서드에는 ‘await’연산자가 없으며 동 기적으로 실행됩니다. ‘await’연산자를 사용하여 비 차단 API 호출을 기다리거나 ‘await Task.Run (…)’을 사용하여 백그라운드 스레드에서 CPU 바운드 작업을 수행하는 것을 고려하십시오.
답변
일부 비동기 기능이있는 인터페이스가 있습니다.
반환하는 방법 Task
, 나는 믿는다. async
구현 세부 사항이므로 인터페이스 메서드에 적용 할 수 없습니다.
인터페이스를 구현하는 일부 클래스는 기다릴 것이 없으며 일부는 그냥 던질 수 있습니다.
이러한 경우에는 다음과 같은 사실을 활용할 수 있습니다. async
구현 세부 사항 .
에 아무것도 없으면 await
다음을 반환 할 수 있습니다 Task.FromResult
.
public Task<int> Success() // note: no "async"
{
... // non-awaiting code
int result = ...;
return Task.FromResult(result);
}
throwing의 경우 NotImplementedException
절차는 좀 더 장황합니다.
public Task<int> Fail() // note: no "async"
{
var tcs = new TaskCompletionSource<int>();
tcs.SetException(new NotImplementedException());
return tcs.Task;
}
던지는 메서드가 많으면 NotImplementedException
(그 자체로 디자인 수준의 리팩토링이 좋을 수 있음을 나타낼 수 있음) 단어를 도우미 클래스로 래핑 할 수 있습니다.
public static class TaskConstants<TResult>
{
static TaskConstants()
{
var tcs = new TaskCompletionSource<TResult>();
tcs.SetException(new NotImplementedException());
NotImplemented = tcs.Task;
}
public static Task<TResult> NotImplemented { get; private set; }
}
public Task<int> Fail() // note: no "async"
{
return TaskConstants<int>.NotImplemented;
}
도우미 클래스는 또한 GC가 수집해야하는 가비지를 줄입니다. 동일한 반환 유형을 가진 각 메서드는 해당 Task
및NotImplementedException
개체를 입니다.
내 AsyncEx 라이브러리에 몇 가지 다른 “작업 상수”유형 예제가 있습니다 .
답변
또 다른 옵션은 함수 본문을 단순하게 유지하고이를 지원하는 코드를 작성하지 않으려는 경우 #pragma로 경고를 억제하는 것입니다.
#pragma warning disable 1998
public async Task<object> Test()
{
throw new NotImplementedException();
}
#pragma warning restore 1998
이것이 충분히 일반적인 경우 파일 맨 위에 disable 문을 배치하고 복원을 생략 할 수 있습니다.
http://msdn.microsoft.com/en-us/library/441722ys(v=vs.110).aspx
답변
async 키워드를 보존하는 또 다른 방법 (보존하려는 경우)은 다음을 사용하는 것입니다.
public async Task StartAsync()
{
await Task.Yield();
}
메소드를 채우면 간단히 명령문을 제거 할 수 있습니다. 나는 특히 메소드가 무언가를 기다리고 있지만 모든 구현이 실제로는 그렇지 않을 때 이것을 많이 사용합니다.
답변
솔루션과 엄밀히 말하면 호출자가 비동기 메서드를 호출하는 방법을 알아야하지만 메서드 결과에서 ” .Wait ()”를 가정하는 기본 사용 패턴을 사용하면 ” return Task.CompletedTask “가 최상의 솔루션입니다.
BenchmarkDotNet=v0.10.11, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.192)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233537 Hz, Resolution=309.2589 ns, Timer=TSC
.NET Core SDK=2.1.2
[Host] : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
Clr : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2600.0
Core : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
Method | Job | Runtime | Mean | Error | StdDev | Median | Min | Max | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated |
--------------- |----- |-------- |-------------:|------------:|------------:|-------------:|-------------:|-------------:|-----:|-------:|-------:|-------:|----------:|
CompletedAwait | Clr | Clr | 95.253 ns | 0.7491 ns | 0.6641 ns | 95.100 ns | 94.461 ns | 96.557 ns | 7 | 0.0075 | - | - | 24 B |
Completed | Clr | Clr | 12.036 ns | 0.0659 ns | 0.0617 ns | 12.026 ns | 11.931 ns | 12.154 ns | 2 | 0.0076 | - | - | 24 B |
Pragma | Clr | Clr | 87.868 ns | 0.3923 ns | 0.3670 ns | 87.789 ns | 87.336 ns | 88.683 ns | 6 | 0.0075 | - | - | 24 B |
FromResult | Clr | Clr | 107.009 ns | 0.6671 ns | 0.6240 ns | 107.009 ns | 106.204 ns | 108.247 ns | 8 | 0.0584 | - | - | 184 B |
Yield | Clr | Clr | 1,766.843 ns | 26.5216 ns | 24.8083 ns | 1,770.383 ns | 1,705.386 ns | 1,800.653 ns | 9 | 0.0877 | 0.0038 | 0.0019 | 320 B |
CompletedAwait | Core | Core | 37.201 ns | 0.1961 ns | 0.1739 ns | 37.227 ns | 36.970 ns | 37.559 ns | 4 | 0.0076 | - | - | 24 B |
Completed | Core | Core | 9.017 ns | 0.0690 ns | 0.0577 ns | 9.010 ns | 8.925 ns | 9.128 ns | 1 | 0.0076 | - | - | 24 B |
Pragma | Core | Core | 34.118 ns | 0.4576 ns | 0.4281 ns | 34.259 ns | 33.437 ns | 34.792 ns | 3 | 0.0076 | - | - | 24 B |
FromResult | Core | Core | 46.953 ns | 1.2728 ns | 1.1905 ns | 46.467 ns | 45.674 ns | 49.868 ns | 5 | 0.0533 | - | - | 168 B |
Yield | Core | Core | 2,480.980 ns | 199.4416 ns | 575.4347 ns | 2,291.978 ns | 1,810.644 ns | 4,085.196 ns | 10 | 0.0916 | - | - | 296 B |
참고 : FromResult
직접 비교할 수 없습니다.
테스트 코드 :
[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
[ClrJob, CoreJob]
[HtmlExporter, MarkdownExporter]
[MemoryDiagnoser]
public class BenchmarkAsyncNotAwaitInterface
{
string context = "text context";
[Benchmark]
public int CompletedAwait()
{
var t = new CompletedAwaitTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int Completed()
{
var t = new CompletedTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int Pragma()
{
var t = new PragmaTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int Yield()
{
var t = new YieldTest();
var a = t.DoAsync(context);
a.Wait();
return t.Length;
}
[Benchmark]
public int FromResult()
{
var t = new FromResultTest();
var t2 = t.DoAsync(context);
return t2.Result;
}
public interface ITestInterface
{
int Length { get; }
Task DoAsync(string context);
}
class CompletedAwaitTest : ITestInterface
{
public int Length { get; private set; }
public async Task DoAsync(string context)
{
Length = context.Length;
await Task.CompletedTask;
}
}
class CompletedTest : ITestInterface
{
public int Length { get; private set; }
public Task DoAsync(string context)
{
Length = context.Length;
return Task.CompletedTask;
}
}
class PragmaTest : ITestInterface
{
public int Length { get; private set; }
#pragma warning disable 1998
public async Task DoAsync(string context)
{
Length = context.Length;
return;
}
#pragma warning restore 1998
}
class YieldTest : ITestInterface
{
public int Length { get; private set; }
public async Task DoAsync(string context)
{
Length = context.Length;
await Task.Yield();
}
}
public interface ITestInterface2
{
Task<int> DoAsync(string context);
}
class FromResultTest : ITestInterface2
{
public async Task<int> DoAsync(string context)
{
var i = context.Length;
return await Task.FromResult(i);
}
}
}
답변
나는 이것이 오래된 스레드라는 것을 알고 있으며 아마도 이것은 모든 사용에 대해 올바른 효과를 갖지 못할 것입니다. 그러나 다음은 아직 메서드를 구현하지 않았을 때 단순히 NotImplementedException을 던질 수있는만큼 가깝습니다. 메서드 서명을 변경하지 않고. 문제가 있다면 알고 있으면 좋겠지 만 나에게는 거의 중요하지 않습니다. 어쨌든 개발 중일 때만 사용하므로 성능이 그다지 중요하지 않습니다. 그래도 나는 그것이 왜 나쁜 생각인지에 대해 듣고 기뻐할 것입니다.
public async Task<object> test()
{
throw await new AwaitableNotImplementedException<object>();
}
이를 가능하게하기 위해 추가 한 유형은 다음과 같습니다.
public class AwaitableNotImplementedException<TResult> : NotImplementedException
{
public AwaitableNotImplementedException() { }
public AwaitableNotImplementedException(string message) : base(message) { }
// This method makes the constructor awaitable.
public TaskAwaiter<AwaitableNotImplementedException<TResult>> GetAwaiter()
{
throw this;
}
}
답변
Stephen의 답변에 대한 업데이트와 마찬가지로 TaskConstants
새로운 도우미 메서드가 있으므로 더 이상 클래스 를 작성할 필요가 없습니다 .
public Task ThrowException()
{
try
{
throw new NotImplementedException();
}
catch (Exception e)
{
return Task.FromException(e);
}
}
답변
이미 Reactive Extension에 링크 한 경우 다음을 수행 할 수도 있습니다.
public async Task<object> NotImplemented()
{
await Observable.Throw(new NotImplementedException(), null as object).ToTask();
}
public async Task<object> SimpleResult()
{
await Observable.Return(myvalue).ToTask();
}
Reactive 및 async / await는 그 자체로도 훌륭하지만 함께 잘 작동합니다.
필요한 것은 다음과 같습니다.
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;