CS1998 चेतावनी को दबाएं: इस एस्किंट विधि में 'वेट' का अभाव है


104

मुझे कुछ async फ़ंक्शंस के साथ एक इंटरफ़ेस मिला है। इंटरफ़ेस को लागू करने वाले कुछ वर्गों के पास प्रतीक्षा करने के लिए कुछ भी नहीं है, और कुछ बस फेंक सकते हैं। यह सभी चेतावनियों से थोड़ा परेशान है।

जब एक async फ़ंक्शन में प्रतीक्षा का उपयोग नहीं किया जाता है।

क्या संदेश को दबाना संभव है?

public async Task<object> test()
{
    throw new NotImplementedException();
}

CS1998 को चेतावनी देते हुए: इस async विधि में ऑपरेटरों की 'प्रतिक्षा' का अभाव है और यह समकालिक रूप से चलेगा। नॉन-ब्लॉकिंग एपीआई कॉल का इंतजार करने के लिए 'वेट' ऑपरेटर का उपयोग करने पर विचार करें, या बैकग्राउंड थ्रेड पर सीपीयू-बाउंड काम करने के लिए 'टास्क.रुन (...)' का इंतजार करें।


1
जब कोई फ़ंक्शन के रूप में async के रूप में चिह्नित नए प्रतीक्षा कीवर्ड का उपयोग नहीं कर रहा है।
साइमन

कैसे हमें एक कोड नमूना दिखाने के बारे में जो समस्या को पुन: पेश करता है?
जॉन सॉन्डर्स

जवाबों:


106

मुझे कुछ async फ़ंक्शंस के साथ एक इंटरफ़ेस मिला है।

लौटने के तरीके Task, मेरा मानना ​​है। asyncएक कार्यान्वयन विवरण है, इसलिए इसे इंटरफ़ेस विधियों पर लागू नहीं किया जा सकता है।

इंटरफ़ेस को लागू करने वाले कुछ वर्गों के पास प्रतीक्षा करने के लिए कुछ भी नहीं है, और कुछ बस फेंक सकते हैं।

इन मामलों में, आप इस तथ्य का लाभ उठा सकते हैं कि asyncकार्यान्वयन विवरण है।

यदि आपके पास कुछ नहीं है await, तो आप बस वापस आ सकते हैं Task.FromResult:

public Task<int> Success() // note: no "async"
{
  ... // non-awaiting code
  int result = ...;
  return Task.FromResult(result);
}

फेंकने के मामले में 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;
}

सहायक वर्ग कचरा भी कम करता है जिसे जीसी को अन्यथा इकट्ठा करना होगा, क्योंकि प्रत्येक विधि उसी रिटर्न प्रकार के साथ अपने Taskऔर NotImplementedExceptionवस्तुओं को साझा कर सकती है ।

मेरे पास अपने AsyncEx लाइब्रेरी में कई अन्य "कार्य स्थिर" प्रकार के उदाहरण हैं


1
मैंने कीवर्ड खोने के बारे में नहीं सोचा था। जैसा कि आप कहते हैं, async को इंटरफ़ेस से कोई लेना देना नहीं है। मेरा बुरा, शुक्रिया।
सिमोन

3
क्या आप एक दृष्टिकोण की सिफारिश कर सकते हैं जहां रिटर्न प्रकार केवल टास्क है (परिणाम के बिना?)
माइक

9
चेतावनी: यह दृष्टिकोण समस्याओं का कारण बन सकता है क्योंकि त्रुटियों को आपके द्वारा अपेक्षित तरीके से प्रचारित नहीं किया जाएगा। आम तौर पर फोन करने वाले को आपके तरीके में अपवाद की उम्मीद होगी Task। इसके बजाय, आपका तरीका इससे पहले कि यह भी एक मौका बनाने के लिए फेंक देंगे एक Task। मुझे वास्तव में लगता है कि सबसे अच्छा पैटर्न एक ऐसी asyncविधि है जिसे बिना awaitऑपरेटरों के साथ परिभाषित करना है । यह उस पद्धति के भीतर कोड को सुनिश्चित करता है जिसे सभी के हिस्से के रूप में माना जाता है Task
बॉब मेयर्स

11
CS1998 से बचने के लिए, आप await Task.FromResult(0);अपनी विधि में जोड़ सकते हैं । यह कोई महत्वपूर्ण पूर्ण प्रभाव नहीं होना चाहिए (टास्क.यिल्ड () के विपरीत)।
बॉब मेयर्स

3
@AndrewTheken: इन दिनों आप बस कर सकते हैं return Task.CompletedTask;- सबसे सरल।
स्टीफन क्लीयर

63

एक अन्य विकल्प, यदि आप फ़ंक्शन के शरीर को सरल रखना चाहते हैं और इसे समर्थन करने के लिए कोड नहीं लिखते हैं, तो बस #pragma के साथ चेतावनी को दबाने के लिए है:

#pragma warning disable 1998
public async Task<object> Test()
{
    throw new NotImplementedException();
}
#pragma warning restore 1998

यदि यह पर्याप्त सामान्य है, तो आप अक्षम कथन को फ़ाइल के शीर्ष पर रख सकते हैं और पुनर्स्थापना को छोड़ सकते हैं।

http://msdn.microsoft.com/en-us/library/441722ys(v=vs.110).aspx


41

Async कीवर्ड को संरक्षित करने का एक और तरीका (यदि आप इसे रखना चाहते हैं) का उपयोग करना है:

public async Task StartAsync()
{
    await Task.Yield();
}

एक बार जब आप विधि को पॉप्युलेट करते हैं तो आप केवल स्टेटमेंट निकाल सकते हैं। मैं इसे बहुत उपयोग करता हूं, खासकर जब कोई विधि किसी चीज का इंतजार कर सकती है, लेकिन हर कार्यान्वयन वास्तव में नहीं करता है।


यह स्वीकृत उत्तर होना चाहिए। कभी-कभी इंटरफ़ेस क्रियान्वयन को async करने की आवश्यकता नहीं होती है, यह एक Task.Runकॉल में सब कुछ लपेटने की तुलना में बहुत क्लीनर है ।
एंड्रयू थेकेन

12
टास्क का इंतजार करें। // एक बेहतर विकल्प हो सकता है
फ्रॉड निल्सन

@ फ्रॉडनील्सन किसी कारण Task.CompletedTaskसे अब मौजूद नहीं है।
सेबेस्टियन वॅनस्टीनिस्टिस्ट

1
@ SebastiánVansteenkiste .Net Framework 4.6->, UWP 1.0->, नेट कोर 1.0->
फ़्रोड निल्सन

1
@AndrewTheken मुझे इस निष्कर्ष पर पहुंचने में थोड़ा समय लगा कि यह उत्तर और आपकी टिप्पणी विशेष रूप से उस मामले पर लागू होती है जहां कार्यान्वयन खाली है या सिर्फ एक अपवाद (मूल प्रश्न के अनुसार) फेंकता है। यदि कोई कार्यान्वयन एक मान लौटाता है, तो ऐसा लगता Task.FromResultहै कि बेहतर उत्तर है। उस मामले के लिए, यदि आप एक अपवाद को फेंकने जा रहे हैं , तो ऐसा लगता है Task.FromExceptionकि यह आदर्श समाधान नहीं है। क्या आप सहमत हैं?
BlueMonkMN

15

समाधानों के बीच अंतर है और कड़ाई से बोलने पर आपको पता होना चाहिए कि कॉल करने वाला कैसे async पद्धति को कॉल करने जा रहा है, लेकिन डिफ़ॉल्ट उपयोग पैटर्न के साथ मानता है ".Wit ()" विधि परिणाम पर - " रिटर्न 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);
        }
    }

}


1
यह दुर्भाग्यपूर्ण है कि #pragmaव्यक्ति को ऊपरी तौर पर उकसाना लगता है। शायद बस उपरि के रूप में ज्यादा के रूप में अगर CompletedTaskआप लौटने के बजाय बनाया और पूरा किया AsyncOperation। संकलक को यह बताने में सक्षम होना अच्छा होगा कि इसे छोड़ना ठीक है जब विधि वैसे भी तुल्यकालिक रूप से चलती है।
बिंकी १५'१

इसी तरह आप कैसे लगता है Task.CompletedTaskके समान है Task.FromResult? यह जानना दिलचस्प होगा - मुझे उम्मीद है कि FromResult सबसे अनुरूप और अभी भी सबसे अच्छा कलाकार होगा यदि आपको एक मूल्य वापस करना है।
BlueMonkMN

मैं इसे जोड़ दूंगा। मुझे लगता है कि राज्य मशीन कोड इस मामले में अधिक क्रियाशील होगा और कंप्लीटटैस्क जीत जाएगा। देखते हैं
रोमन पोक्रोवस्किज

1
.NET कोर 2.2 के लिए इस अद्यतन को देखकर अच्छा लगेगा, क्योंकि async राज्य-मशीनों में आवंटन में अत्यधिक सुधार हुआ है
Tseng

1
@Tseng मैंने .NET कोर 2.2.0 पर बेंचमार्क चलाया है। जाहिर है, अलग-अलग हार्डवेयर के कारण कुल समय अलग-अलग होता है, लेकिन अनुपात लगभग समान ही रहता है: विधि | .NET कोर 2.0.3 मीन | .NET कोर 2.2.0 मतलब पूरा हुआ | 100% | 100% पूर्णतया Await | 412.57% | 377.22% FromResult | 520.72% | 590.89% प्रगति | 378.37% | 346.64% यील्ड | 27514.47% | 23602.38%
तूफान

10

मुझे पता है कि यह एक पुराना धागा है, और शायद यह सभी उपयोगों के लिए सही प्रभाव नहीं होगा, लेकिन निम्नलिखित उतना ही करीब है जितना कि मैं एक 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;
    }
}

10

स्टीफन के जवाब के अपडेट के रूप में, आपको TaskConstantsक्लास लिखने की आवश्यकता नहीं है क्योंकि एक नया सहायक तरीका है:

    public Task ThrowException()
    {
        try
        {
            throw new NotImplementedException();
        }
        catch (Exception e)
        {
            return Task.FromException(e);
        }
    }

3
यह मत करो। स्टैक ट्रेस आपके कोड पर इंगित नहीं होगा। अपवादों को पूरी तरह से शुरू करने के लिए फेंक दिया जाना चाहिए।
डैनियल बी

1
डेनियल बी - हां, आप बिल्कुल सही हैं। मैंने अपवाद को सही ढंग से फेंकने के लिए अपने उत्तर को संशोधित किया है।
मैट

3

यदि आप पहले से ही रिएक्टिव एक्सटेंशन के खिलाफ लिंक करते हैं, तो आप यह भी कर सकते हैं:

public async Task<object> NotImplemented()
{
    await Observable.Throw(new NotImplementedException(), null as object).ToTask();
}

public async Task<object> SimpleResult()
{
    await Observable.Return(myvalue).ToTask();
}

प्रतिक्रियाशील और async / प्रतीक्षा दोनों में और अपने आप में अद्भुत हैं, लेकिन वे भी एक साथ अच्छी तरह से खेलते हैं।

इसमें शामिल हैं:

using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;

3

यह नीचे cs1998 हो सकता है।

public async Task<object> Foo()
{
    return object;
}

तब आप नीचे सुधार कर सकते हैं।

public async Task<object> Foo()
{
    var result = await Task.Run(() =>
    {
        return object;
    });
    return result;
}



1

अगर आपके पास इंतजार करने के लिए कुछ भी नहीं है तो टास्क को वापस लौटाएं। FromResult

public Task<int> Success() // note: no "async"
{
  ... // Do not have await code
  var result = ...;
  return Task.FromResult(result);
}

1

यहां आपके विधि हस्ताक्षर के आधार पर कुछ विकल्प दिए गए हैं।

    public async Task Test1()
    {
        await Task.CompletedTask;
    }

    public async Task<object> Test2()
    {
        return await Task.FromResult<object>(null);
    }

    public async Task<object> Test3()
    {
        return await Task.FromException<object>(new NotImplementedException());
    }

-1
// This is to get rid of warning CS1998, please remove when implementing this method.
await new Task(() => { }).ConfigureAwait(false);
throw new NotImplementedException();

-2

आप async कीवर्ड को विधि से छोड़ सकते हैं और बस इसे टास्क में लौटा सकते हैं;

    public async Task DoTask()
    {
        State = TaskStates.InProgress;
        await RunTimer();
    }

    public Task RunTimer()
    {
        return new Task(new Action(() =>
        {
            using (var t = new time.Timer(RequiredTime.Milliseconds))
            {
                t.Elapsed += ((x, y) => State = TaskStates.Completed);
                t.Start();
            }
        }));
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.