'প্রতীক্ষা' কাজ করে, তবে কলিং টাস্ক es ফলাফলগুলি হ্যাং / ডেডলক করে


126

আমার নিম্নলিখিত চারটি পরীক্ষা রয়েছে এবং আমি চালানোর সময় শেষটি স্তব্ধ হয়ে যায়। কেন এটি ঘটে:

[Test]
public void CheckOnceResultTest()
{
    Assert.IsTrue(CheckStatus().Result);
}

[Test]
public async void CheckOnceAwaitTest()
{
    Assert.IsTrue(await CheckStatus());
}

[Test]
public async void CheckStatusTwiceAwaitTest()
{
    Assert.IsTrue(await CheckStatus());
    Assert.IsTrue(await CheckStatus());
}

[Test]
public async void CheckStatusTwiceResultTest()
{
    Assert.IsTrue(CheckStatus().Result); // This hangs
    Assert.IsTrue(await CheckStatus());
}

private async Task<bool> CheckStatus()
{
    var restClient = new RestClient(@"https://api.test.nordnet.se/next/1");
    Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
    IRestResponse<DummyServiceStatus> response = await restResponse;
    return response.Data.SystemRunning;
}

আমি পুনরায় ভাগ করার জন্য পুনরায় ভাগ করার জন্য এই এক্সটেনশন পদ্ধতিটি ব্যবহার করি :

public static class RestClientExt
{
    public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
    {
        var tcs = new TaskCompletionSource<IRestResponse<T>>();
        RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
        return tcs.Task;
    }
}
public class DummyServiceStatus
{
    public string Message { get; set; }
    public bool ValidVersion { get; set; }
    public bool SystemRunning { get; set; }
    public bool SkipPhrase { get; set; }
    public long Timestamp { get; set; }
}

শেষ পরীক্ষা কেন ঝুলে থাকে?


7
অ্যাসিঙ্ক পদ্ধতি থেকে আপনার অকার্যকর ফিরে আসা উচিত। এটি কেবলমাত্র উপস্থিত ইভেন্ট হ্যান্ডলারের সাথে পিছনে সামঞ্জস্যের জন্য, বেশিরভাগ ইন্টারফেস কোডে। যদি আপনার অ্যাসিঙ্ক পদ্ধতিটি কোনও কিছু না ফেরায়, তবে এটি টাস্কটি ফিরে আসবে। এমএসটিস্ট এবং অকার্যকর এসিএনসি পরীক্ষার সাথে আমার প্রচুর সমস্যা ছিল।
ঘোর্ড

2
@ গর্ড: এমএসটিস্ট async voidইউনিট পরীক্ষার পদ্ধতিগুলি মোটেই সমর্থন করে না ; তারা কেবল কাজ করবে না। তবে নুনিট তা করেন। এটি বলেছে, আমি ওভারকে async Taskপ্রাধান্য দেওয়ার সাধারণ নীতিতে একমত async void
স্টিফেন ক্লিয়ারি

@ স্টেফেনক্রিয়ারি হ্যাঁ, যদিও এটি ভিএস ২০১২ এর বিটাতে অনুমোদিত হয়েছিল, যা সমস্ত ধরণের সমস্যা সৃষ্টি করেছিল।
ঘোর্ড

উত্তর:


88

আপনি আমার ব্লগে এবং একটি এমএসডিএন নিবন্ধে বর্ণনা করছি এমন স্ট্যান্ডলক পরিস্থিতি নিয়ে চলেছেন : asyncপদ্ধতিটি কলটির মাধ্যমে অবরুদ্ধ হওয়া কোনও থ্রেডে এর ধারাবাহিকতা নির্ধারণ করার চেষ্টা করছে Result

এই ক্ষেত্রে, SynchronizationContextNUnit দ্বারা async voidপরীক্ষার পদ্ধতিগুলি কার্যকর করতে আপনার ব্যবহৃত এক । async Taskপরিবর্তে আমি পরীক্ষার পদ্ধতিগুলি ব্যবহার করার চেষ্টা করব ।


4
অ্যাসিঙ্ক টাস্কে কাজ করে কাজ করা হয়েছে, এখন আমাকে কয়েকবার আপনার লিঙ্কগুলির বিষয়বস্তু পড়তে হবে, স্যার।
জোহান লারসন

@ মারিওলোপেজ: সমাধানটি হল " asyncসমস্ত উপায়" (যেমন আমার এমএসডিএন নিবন্ধে উল্লিখিত) ব্যবহার করা। অন্য কথায় - আমার ব্লগ পোস্টের শিরোনাম হিসাবে - "অ্যাসিঙ্ক কোডটি ব্লক করবেন না"।
স্টিফেন ক্লিয়ারি

1
@ স্টেফেনক্রিয়ারি যদি আমাকে কোনও কনস্ট্রাক্টরের ভিতরে একটি অ্যাসিঙ্ক পদ্ধতি কল করতে হয়? নির্মাতারা অ্যাসিঙ্ক হতে পারে না।
রায়কোল আমারো

1
@ স্টেফেনক্লিয়ারি এসও এবং আপনার নিবন্ধগুলিতে আপনার প্রায় সমস্ত জবাবগুলিতে, আমি যে বার্তায় আপনি যা দেখেন তার সবই Wait()কলিংয়ের পদ্ধতিটি প্রতিস্থাপন করে async। তবে আমার কাছে মনে হচ্ছে এটি সমস্যাটিকে উজানে প্রবাহিত করছে। কিছু সময়ে, কিছু সিঙ্ক্রোনালি পরিচালনা করতে হবে। যদি আমার ফাংশন উদ্দেশ্যমূলকভাবে সিঙ্ক্রোনাস হয় কারণ এটি দীর্ঘকাল ধরে চলমান কর্মী থ্রেডগুলি পরিচালনা করে Task.Run()? আমার এনইউনাইট পরীক্ষার মধ্যে ডেডলকিং না করে কীভাবে শেষ করতে পারি?
void.pointer

1
@ void.pointer: At some point, something has to be managed synchronously.- মোটেও নয়। ইউআই অ্যাপ্লিকেশনগুলির জন্য, এন্ট্রিপয়েন্টটি async voidইভেন্ট হ্যান্ডলার হতে পারে । সার্ভার অ্যাপ্লিকেশনগুলির জন্য, এন্ট্রিপয়েন্টটি কোনও async Task<T>ক্রিয়া হতে পারে । asyncথ্রেড ব্লক করা এড়াতে উভয়ের পক্ষে ব্যবহার করা ভাল । আপনার NUnit পরীক্ষাটি সিঙ্ক্রোনাস বা অ্যাসিঙ্ক হতে পারে; যদি অ্যাসিঙ্ক হয় তবে এটির async Taskপরিবর্তে তৈরি করুন async void। যদি এটি সিঙ্ক্রোনাস হয় তবে এটির SynchronizationContextএকটি অচলাবস্থা না থাকা উচিত।
স্টিফেন ক্লিয়ারি

222

একটি অ্যাসিঙ্ক পদ্ধতির মাধ্যমে একটি মান অর্জন করা:

var result = Task.Run(() => asyncGetValue()).Result;

সুসংগতভাবে একটি অ্যাসিঙ্ক পদ্ধতিতে কল করা হচ্ছে

Task.Run( () => asyncMethod()).Wait();

টাস্ক.রুন ব্যবহারের কারণে কোনও অচলাবস্থার সমস্যা দেখা দেবে না।


15
-1 async voidইউনিট পরীক্ষা পদ্ধতি ব্যবহারে উত্সাহিত করার জন্য এবং পরীক্ষার SynchronizationContextঅধীনে সিস্টেমের দ্বারা সরবরাহিত একই থ্রেড গ্যারান্টি অপসারণ করার জন্য।
স্টিফেন ক্লিয়ারি

68
@ স্টেফেনক্রিয়ারি: অ্যাসিঙ্ক শূন্যতার কোনও "উত্সাহ" নেই। এটি কেবল অচলাবস্থার সমস্যা সমাধানের জন্য বৈধ সি # কনস্ট্রাক্ট নিয়োগ করছে। উপরের স্নিপেটটি ওপি'র ইস্যুটির জন্য একটি অনিবার্য এবং সহজ কাজ। স্ট্যাকওভারফ্লো সমস্যাগুলির স্বাবলম্বন নয়, সমস্যার সমাধান সম্পর্কিত।
হারমান শোয়েনফিল্ড

81
@ স্টেফেনক্রিয়ারি: আপনার নিবন্ধগুলি সমাধানটি প্রকৃতপক্ষে স্পষ্টভাবে প্রকাশ করে না (কমপক্ষে পরিষ্কারভাবে নয়) এবং এমনকি যদি আপনার কোনও সমাধান থাকে তবে আপনি এই ধরনের নির্মাণগুলি পরোক্ষভাবে ব্যবহার করতে চাইবেন। আমার সমাধান স্পষ্টভাবে প্রসঙ্গ ব্যবহার করে না, তাইলে কী? মুল বক্তব্যটি হ'ল, আমার কাজ করে এবং এটি ওয়ান লাইনার। সমস্যাটি সমাধান করতে দুটি ব্লগ পোস্ট এবং কয়েক হাজার শব্দের দরকার নেই। দ্রষ্টব্য: আমি এমনকি অ্যাসিঙ্ক শূন্যতাও ব্যবহার করি না , তাই আপনি কী করছেন তা সত্যিই আমি জানি না you আপনি আমার সংক্ষিপ্ত এবং যথাযথ উত্তরের যে কোনও জায়গায় "অ্যাসিঙ্ক অকার্যকর" দেখতে পাচ্ছেন?
হারমান শোয়েনফিল্ড

15
, @HermanSchoenfeld যদি জুড়েছে কেন করতে কিভাবে , আমি বিশ্বাস করি আপনার উত্তর অনেক উপকার হবে।
আয়রনস্টোন 13

19
আমি জানি যে এটি দেরীের মতো, তবে আপনার .GetAwaiter().GetResult()পরিবর্তে .Resultএমনটি ব্যবহার করা উচিত যাতে কোনও Exceptionআবৃত না হয়।
ক্যামিলো তেরেভিনতো

15

আপনি ConfigureAwait(false)এই লাইনে অচলাবস্থা এড়াতে পারবেন :

IRestResponse<DummyServiceStatus> response = await restResponse;

=>

IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false);

আমি আমার ব্লগ পোস্টে অ্যাসিঙ্ক / অপেক্ষার অসুবিধাগুলি পোস্ট করেছি


9

আপনি টাস্ক.সম্পূর্ণ সম্পত্তি ব্যবহার করে ইউআইকে অবরুদ্ধ করছেন। ইন MSDN ডকুমেন্টেশন তারা পরিষ্কারভাবে উল্লেখ করেছি যে,

" ফলাফল সম্পত্তি একটি ব্লক করা সম্পত্তি। যদি আপনি এটির কাজ শেষ হওয়ার আগে এটি অ্যাক্সেস করার চেষ্টা করেন তবে কার্যত সক্রিয় থ্রেডটি টাস্কটি সম্পূর্ণ না হওয়া অবধি অবরুদ্ধ হয়ে যায় এবং মানটি উপলব্ধ না হয় most বেশিরভাগ ক্ষেত্রেই আপনার অপেক্ষাটি ব্যবহার করে মানটি অ্যাক্সেস করা উচিত অথবা সরাসরি সম্পত্তি অ্যাক্সেস না করে অপেক্ষা করুন ""

এই দৃশ্যের সর্বোত্তম সমাধান হ'ল পদ্ধতিগুলি থেকে অপেক্ষারত এবং অ্যাসিঙ্ক উভয়কেই সরিয়ে দেওয়া এবং আপনি যে ফলাফলটি দেখছেন সেখানে কেবলমাত্র টাস্ক ব্যবহার করা । এটি আপনার মৃত্যুদন্ডের ক্রমকে বিশৃঙ্খলা করবে না।


3

পরিষেবা / API async ফাংশন কল করার পরে যদি আপনি কোনও কলব্যাক না পান বা নিয়ন্ত্রণটি স্তব্ধ হয়ে যায়, আপনাকে একই ডাকা প্রসঙ্গে ফলাফল ফেরত দিতে কনটেক্সটটি কনফিগার করতে হবে।

ব্যবহার TestAsync().ConfigureAwait(continueOnCapturedContext: false);

আপনি কেবল ওয়েব অ্যাপ্লিকেশনগুলিতে এই সমস্যার মুখোমুখি হবেন, তবে তা নয় static void main


ConfigureAwaitমূল থ্রেড প্রসঙ্গে না চালিয়ে নির্দিষ্ট পরিস্থিতিতে ডেডলকিং এড়ানো।
ডেভিডকারার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.