অ্যাসিঙ্ক পদ্ধতিটি সিঙ্ক্রোনালি কল করা হচ্ছে


230

আমার একটি asyncপদ্ধতি রয়েছে:

public async Task<string> GenerateCodeAsync()
{
    string code = await GenerateCodeService.GenerateCodeAsync();
    return code;
}

একটি সিঙ্ক্রোনাস পদ্ধতি থেকে আমাকে এই পদ্ধতিটি কল করতে হবে।

এটি GenerateCodeAsyncসিঙ্ক্রোনসিভভাবে কাজ করার জন্য পদ্ধতিটির সদৃশ না করে কীভাবে এটি করতে পারি ?

হালনাগাদ

তবুও কোন যুক্তিসঙ্গত সমাধান খুঁজে পাওয়া যায় নি।

তবে, আমি দেখতে পাচ্ছি যে HttpClientইতিমধ্যে এই প্যাটার্নটি প্রয়োগ করে ments

using (HttpClient client = new HttpClient())
{
    // async
    HttpResponseMessage responseAsync = await client.GetAsync(url);

    // sync
    HttpResponseMessage responseSync = client.GetAsync(url).Result;
}


1
আমি একটি সহজ সমাধানের জন্য আশা করছিলাম, এই ভেবে যে এসপ নেট এতগুলি কোড কোডের লেখার চেয়ে সহজভাবে পরিচালনা করেছে
কাতালিন

কেন কেবল অ্যাসিঙ্ক কোডটি আলিঙ্গন করবেন না? আদর্শভাবে আপনি আরও অ্যাসিঙ্ক কোড চান, কম নয়।
পাওলো মোরগাদো

53
[কেন কেবল অ্যাসিঙ্ক কোডটি আলিঙ্গন করবেন না?] হ্যাঁ, এটি সম্ভবত অবিলম্বে হতে পারে কারণ একজন অ্যাসিঙ্ক কোডটি গ্রহণ করছেন যেহেতু প্রকল্পের বৃহত অংশগুলি রূপান্তরিত হওয়ার সাথে সাথে তাদের এই সমাধান প্রয়োজন! আপনি একদিনে রোম পুনর্নির্মাণ করতে পারবেন না।
নিকোলাস পিটারসেন

1
@ নিকোলাস পিটারসন কখনও কখনও তৃতীয় পক্ষের লাইব্রেরি আপনাকে এটি করতে বাধ্য করতে পারে। ফ্লুভেন্টিলেশন ছাড়াই উইথমেসেজ পদ্ধতিতে গতিশীল বার্তা তৈরির উদাহরণ। লাইব্রেরি ডিজাইনের কারণে এর জন্য কোনও অ্যাসিঙ্ক এপিআই নেই - উইথমেসেজ ওভারলোডগুলি স্থির। WithMessage এ গতিশীল আর্গুমেন্ট পাস করার অন্যান্য পদ্ধতিগুলি অদ্ভুত।
এইচ.ওজটোউইচজ

উত্তর:


278

আপনি কার্যটির Resultসম্পত্তিটি অ্যাক্সেস করতে পারবেন , ফলাফলটি না পাওয়া পর্যন্ত আপনার থ্রেডটি ব্লক করে দেবে:

string code = GenerateCodeAsync().Result;

দ্রষ্টব্য: কিছু ক্ষেত্রে, এটি একটি অচলাবস্থার দিকে পরিচালিত করতে পারে: আপনার কলটি Resultমূল থ্রেডকে ব্লক করে, ফলে অ্যাসিঙ্ক কোডটি চালিয়ে যাওয়ার বাকি রোধ করে। এটি যাতে না ঘটে তা নিশ্চিত করার জন্য আপনার নীচের বিকল্পগুলি রয়েছে:

এর অর্থ এই নয় যে আপনার .ConfigureAwait(false)সমস্ত অ্যাসিঙ্ক কল করার পরে আপনার কেবল নির্বোধভাবে যোগ করা উচিত ! আপনার কখন এবং কখন ব্যবহার করা উচিত সে সম্পর্কে বিশদ বিশ্লেষণের .ConfigureAwait(false)জন্য নীচের ব্লগ পোস্টটি দেখুন:


33
যদি অনুরোধ করা resultএকটি অচলাবস্থা ঝুঁকিপূর্ণ হয়, তবে ফলাফলটি পাওয়া কখন নিরাপদ? প্রতিটি অ্যাসিক্রোনাস কল প্রয়োজন হয় Task.Runবা ConfigureAwait(false)?
রবার্ট হার্ভে

4
AspNetSynchronizationContext.PostTask newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action)); _lastScheduledTask = newTask;
এএসপি.নেটে

4
@ রবার্তাহারভে: আপনি যে অ্যাসিঙ্ক পদ্ধতিটি অবরুদ্ধ করছেন তা বাস্তবায়নের যদি আপনার কোনও নিয়ন্ত্রণ না থাকে তবে হ্যাঁ, Task.Runনিরাপদ থাকার জন্য আপনার এটি আবদ্ধ করা উচিত । বা WithNoContextরিডানড্যান্ট থ্রেড স্যুইচিং হ্রাস করার মতো কিছু ব্যবহার করুন ।
নাকেরটিও

10
দ্রষ্টব্য: .Resultকলার নিজেই থ্রেড পুলে থাকলে কল করা এখনও অচল হয়ে যেতে পারে। থ্রেড পুলটি 32 মিমি আকারের 32 এবং 32 টি কার্য চলছে এবং Wait()/Resultএকটি অপেক্ষার থ্রেডে চলতে চায় এমন একটি এখনও নির্ধারিত-নির্ধারিত 33 তম টাস্কের জন্য অপেক্ষা করছে এমন একটি দৃশ্য দেখুন।
ওয়ার্টি

55

আপনার প্রতীক্ষক ( GetAwaiter()) পাওয়া উচিত এবং অ্যাসিক্রোনাস টাস্ক ( GetResult()) সমাপ্তির জন্য অপেক্ষা শেষ করা উচিত ।

string code = GenerateCodeAsync().GetAwaiter().GetResult();

37
আমরা এই সমাধানটি ব্যবহার করে অচলাবস্থায় চলে এসেছি। সতর্কাবস্থা.
অলিভার

6
এমএসডিএনTask.GetAwaiter : এই পদ্ধতিটি অ্যাপ্লিকেশন কোডে ব্যবহারের পরিবর্তে সংকলক ব্যবহারের উদ্দেশ্যে।
ফোকা

তবুও ত্রুটিটি পেয়েছি ডায়ালগ পপআপ (আমার ইচ্ছার বিরুদ্ধে), 'বাছাই করুন' বা 'পুনরায় চেষ্টা করুন' বোতামগুলির সাথে ...। যাইহোক, কলটি আসলে কার্যকর করে এবং একটি উপযুক্ত প্রতিক্রিয়া দিয়ে ফিরে আসে।
জোনাথন হানসেন

30

আপনার প্রতিনিধি, ল্যাম্বডা এক্সপ্রেশন ব্যবহার করে এটি সম্পন্ন করতে সক্ষম হওয়া উচিত

private void button2_Click(object sender, EventArgs e)
    {

        label1.Text = "waiting....";

        Task<string> sCode = Task.Run(async () =>
        {
            string msg =await GenerateCodeAsync();
            return msg;
        });

        label1.Text += sCode.Result;

    }

    private Task<string> GenerateCodeAsync()
    {
        return Task.Run<string>(() => GenerateCode());
    }

    private string GenerateCode()
    {
        Thread.Sleep(2000);
        return "I m back" ;
    }

এই স্নিপেট সংকলন করবে না। টাস্ক.রুন থেকে রিটার্ন টাইপ হ'ল টাস্ক। সম্পূর্ণ ব্যাখ্যার জন্য এই এমএসডিএন ব্লগটি দেখুন ।
অ্যাপিটিরে

5
নির্দেশ করার জন্য ধন্যবাদ, হ্যাঁ এটি টাস্ক টাইপ দেয়। "স্ট্রিং এসকোড" কে টাস্ক <স্ট্রিং> বা ভের এসকোডে প্রতিস্থাপন করলে এটি সমাধান করা উচিত। স্বাচ্ছন্দ্যের জন্য একটি সম্পূর্ণ সংকলন কোড যুক্ত করা হচ্ছে।
ফাইয়াজ

20

একটি সিঙ্ক্রোনাস পদ্ধতিতে আমাকে এই পদ্ধতিটি কল করতে হবে।

অন্যান্য উত্তর হিসাবে যেমন এটির সাথে GenerateCodeAsync().Resultবা এটি সম্ভব possible এটি সম্পূর্ণ GenerateCodeAsync().Wait()না হওয়া পর্যন্ত বর্তমান থ্রেডটিকে অবরুদ্ধ করবে GenerateCodeAsync

যাইহোক, আপনার প্রশ্ন ট্যাগ করা হয় , এবং আপনি মন্তব্যটি রেখে গেছেন:

আমি একটি সহজ সমাধানের জন্য আশা করছিলাম, ভেবেছিলাম যে এসপ নেট কোডের এতগুলি লাইন লেখার চেয়ে এটিকে আরও সহজ করে তোলে

আমার বক্তব্যটি হ'ল, আপনাকে এএসপি.নেটে কোনও অ্যাসিঙ্ক্রোনাস পদ্ধতিতে অবরুদ্ধ করা উচিত নয় । এটি আপনার ওয়েব অ্যাপ্লিকেশনটির স্কেলিবিলিটি হ্রাস করবে এবং একটি অচলাবস্থা তৈরি করতে পারে (যখন কোনও awaitধারাবাহিকতা ভিতরে GenerateCodeAsyncপোস্ট করা হয় AspNetSynchronizationContext)। ব্যবহার Task.Run(...).Resultবৃদ্ধির আরও বেশি, একটি পুল থ্রেড এবং তারপর ব্লক অফলোড কিছু ক্ষতি করতে পারবে যেমন একটি প্রদত্ত HTTP অনুরোধ প্রক্রিয়া করতে আরও +1 থ্রেড incurs।

ASP.NET মাধ্যমে বিল্ট-ইন করেছে অ্যাসিঙ্ক্রোনাস পদ্ধতির জন্য সমর্থন, হয় অ্যাসিঙ্ক্রোনাস কন্ট্রোলার মাধ্যমে (ASP.NET MVC ওয়েব এপিআই এবং) অথবা সরাসরি AsyncManagerএবং PageAsyncTaskসর্বোত্তম ASP.NET হবে। আপনার এটি ব্যবহার করা উচিত। আরও তথ্যের জন্য, এই উত্তরটি দেখুন


আমি এর SaveChanges()পদ্ধতিটি ওভাররাইট করছি DbContextএবং এখানে আমি অ্যাসিঙ্ক পদ্ধতিগুলি কল করছি, তাই দুর্ভাগ্যক্রমে async নিয়ামক আমাকে এই পরিস্থিতিতে সাহায্য করবে না
ক্যাটালিন

3
@ রারািটল, সাধারণভাবে, আপনি অ্যাসিঙ্ক এবং সিঙ্ক কোডটি মিশ্রন করেন না, ইথার মডেলটি বেছে নেন। আপনি উভয়ই বাস্তবায়ন করতে পারেন SaveChangesAsyncএবং SaveChangesকেবল একই এএসপি.নেট প্রকল্পে তারা উভয়কেই ডেকে না পেয়েছে তা নিশ্চিত করুন।
নাসেরটিও

4
সমস্ত .NET MVCফিল্টার অ্যাসিক্রোনাস কোড সমর্থন করে না , উদাহরণস্বরূপ IAuthorizationFilter, তাই আমি asyncসমস্ত উপায়ে ব্যবহার করতে পারি না
ক্যাটালিন

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

9
@ নোসরাতো, প্রশ্নটি সিঙ্ক্রোনাস থেকে অ্যাসিক্রোনাস পদ্ধতি কল করার বিষয়ে। আপনি প্রয়োগকারী এপিআই কখনও কখনও পরিবর্তন করতে পারবেন না। ধরা যাক আপনি কিছু 3-তম পার্টির কাঠামো "এ" (আপনি কাঠামোটিকে অবিচ্ছিন্ন পদ্ধতিতে পুনরায় লিখতে পারবেন না) থেকে কিছু সংশ্লেষপূর্ণ ইন্টারফেস প্রয়োগ করছেন তবে তৃতীয় পক্ষের লাইব্রেরি "বি" আপনার প্রয়োগের জন্য ব্যবহার করার চেষ্টা করছেন কেবলমাত্র অ্যাসিনক্রোনাস। ফলস্বরূপ
পণ্যটিও

19

মাইক্রোসফ্ট আইডেন্টিটির এক্সটেনশন পদ্ধতি রয়েছে যা অ্যাসিঙ্ক পদ্ধতিগুলিকে সিঙ্ক্রোনালি কল করে। উদাহরণস্বরূপ জেনারেট ইউজারআইডেন্টিটিএেন্সিক () পদ্ধতি এবং সমান ক্রিয়েইডিটেন্টিটি () রয়েছে

আপনি যদি ইউজারম্যানেজারএক্সটেনশনগুলি দেখুন re

 public static ClaimsIdentity CreateIdentity<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user,
        string authenticationType)
        where TKey : IEquatable<TKey>
        where TUser : class, IUser<TKey>
    {
        if (manager == null)
        {
            throw new ArgumentNullException("manager");
        }
        return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType));
    }

এখন আসিহেলহেল্পার.রুনসাইক কী করে তা দেখতে দিন nc

  public static TResult RunSync<TResult>(Func<Task<TResult>> func)
    {
        var cultureUi = CultureInfo.CurrentUICulture;
        var culture = CultureInfo.CurrentCulture;
        return _myTaskFactory.StartNew(() =>
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = cultureUi;
            return func();
        }).Unwrap().GetAwaiter().GetResult();
    }

সুতরাং, এটি অ্যাসিঙ্ক পদ্ধতির জন্য আপনার মোড়ক। এবং দয়া করে ফলাফল থেকে ডেটা পড়বেন না - এটি সম্ভাব্যত আপনার কোডটিকে এএসপিতে ব্লক করবে।

আরও একটি উপায় আছে - যা আমার জন্য সন্দেহজনক তবে আপনি এটিও বিবেচনা করতে পারেন

  Result r = null;

            YourAsyncMethod()
                .ContinueWith(t =>
                {
                    r = t.Result;
                })
                .Wait();

3
আপনি দ্বিতীয়বার পরামর্শ দেওয়ার বিষয়টি কী বলে বিবেচনা করবেন?
ডেভিড ক্লার্ক

@ ডেভিড ক্লার্ক সম্ভবত লক ছাড়াই একাধিক থ্রেড থেকে অ-উদ্বায়ী ভেরিয়েবল অ্যাক্সেসের থ্রেড সুরক্ষা ইস্যু।
থিওডর জৌলিয়াস

9

অচলাবস্থা রোধ করতে আমি সর্বদা ব্যবহার করার চেষ্টা করি Task.Run()যখন আমাকে হিঞ্জি উল্লেখ করেছে সিঙ্ক্রোনালি একটি অ্যাসিঙ্ক পদ্ধতিতে কল করতে হবে।

তবে অ্যাসিঙ্ক পদ্ধতিটি যদি প্যারামিটার ব্যবহার করে তবে পদ্ধতিটি পরিবর্তন করতে হবে। উদাহরণস্বরূপ Task.Run(GenerateCodeAsync("test")).Resultত্রুটি দেয়:

যুক্তি 1: ' System.Threading.Tasks.Task<string>' থেকে 'সিস্টেম.অ্যাকশন' এ রূপান্তর করতে পারে না

পরিবর্তে এটি বলা যেতে পারে:

string code = Task.Run(() => GenerateCodeAsync("test")).Result;

5

এই থ্রেডের বেশিরভাগ উত্তর হয় জটিল হয় বা ফলাফল অচলাবস্থার ফলস্বরূপ।

নিম্নলিখিত পদ্ধতিটি সহজ এবং এটি অচলাবস্থা এড়াতে পারবে কারণ আমরা কাজটি শেষ হওয়ার জন্য অপেক্ষা করছি এবং কেবল তার ফলাফল পাওয়ার পরে-

var task = Task.Run(() => GenerateCodeAsync()); 
task.Wait();
string code = task.Result;

অধিকন্তু, এখানে দুটিই MSDN নিবন্ধ একটি রেফারেন্স যে ঠিক একই thing- সম্পর্কে আলোচনা https://blogs.msdn.microsoft.com/jpsanders/2017/08/28/asp-net-do-not-use-task-result- ইন-প্রধান-প্রসঙ্গ /


0

আমি একটি অবরুদ্ধকরণ পদ্ধতির পছন্দ করি:

            Dim aw1=GenerateCodeAsync().GetAwaiter()
            While Not aw1.IsCompleted
                Application.DoEvents()
            End While

0

ভাল আমি এই পদ্ধতির ব্যবহার করছি:

    private string RunSync()
    {
        var task = Task.Run(async () => await GenerateCodeService.GenerateCodeAsync());
        if (task.IsFaulted && task.Exception != null)
        {
            throw task.Exception;
        }

        return task.Result;
    }

-1

অন্য উপায়টি যদি আপনি কাজটি শেষ না হওয়া পর্যন্ত অপেক্ষা করতে চান তবে হতে পারে:

var t = GenerateCodeService.GenerateCodeAsync();
Task.WhenAll(t);
string code = t.Result;

1
এটা সরল ভুল। যখন সমস্তও একটি টাস্ক প্রদান করে, যা আপনি অপেক্ষা করছেন না।
রবার্ট

-1

সম্পাদনা করুন:

টাস্কের ওয়েট পদ্ধতি রয়েছে, টাস্ক.ওয়েট (), এটি সমাধানের "প্রতিশ্রুতি" অপেক্ষা করে এবং পরে অবিরত থাকে, সুতরাং এটি সিঙ্ক্রোনাস উপস্থাপন করে। উদাহরণ:


async Task<String> MyAsyncMethod() { ... }

String mySyncMethod() {

    return MyAsyncMethod().Wait();
}

3
দয়া করে আপনার উত্তরটি বিস্তারিতভাবে বর্ণনা করুন। এটি কীভাবে ব্যবহৃত হয়? প্রশ্নটির উত্তর দিতে এটি কীভাবে বিশেষভাবে সহায়তা করে?
স্ক্র্যাটে

-2

আপনার যদি " রিফ্রেশলিস্ট " নামে একটি অ্যাসিঙ্ক পদ্ধতি থাকে তবে নীচের মতো অ্যাসিঙ্ক পদ্ধতি থেকে আপনি সেই অ্যাসিঙ্ক পদ্ধতিটি কল করতে পারেন।

Task.Run(async () => { await RefreshList(); });
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.