c# - मैं एक एसिंक कार्य<टी> विधि को सिंक्रनाइज़ तरीके से कैसे चलाऊंगा?




asynchronous c#-5.0 (15)

मैं async / प्रतीक्षा के बारे में सीख रहा हूं, और ऐसी परिस्थिति में भाग गया जहां मुझे एक एसिंक विधि को समकालिक रूप से कॉल करने की आवश्यकता है। मैं उसे कैसे कर सकता हूँ?

"स्थिति" क्या है, इस पर निर्भर विवरण के साथ सबसे अच्छा जवाब यह नहीं है।

क्या यह एक संपत्ति गेटर / सेटर है? ज्यादातर मामलों में, "एसिंक्रोनस गुण" से एसिंक्रोनस विधियां बेहतर होती हैं। (अधिक जानकारी के लिए, एसिंक्रोनस गुणों पर मेरा ब्लॉग पोस्ट देखें)।

क्या यह एक एमवीवीएम ऐप है और आप असीमित डेटा बाध्यकारी करना चाहते हैं? फिर मेरे एमएसडीएन आलेख में एसिंक्रोनस डेटा बाइंडिंग पर वर्णित मेरे NotifyTask तरह कुछ उपयोग करें।

क्या यह एक निर्माता है? तो आप शायद एक एसिंक्रोनस फैक्ट्री विधि पर विचार करना चाहते हैं। (अधिक जानकारी के लिए, एसिंक्रोनस कन्स्ट्रक्टर पर मेरा ब्लॉग पोस्ट देखें)।

सिंक-ओवर-एसिंक करने के बजाए लगभग हमेशा एक बेहतर जवाब होता है।

यदि आपकी स्थिति के लिए यह संभव नहीं है (और आप स्थिति का वर्णन करने वाले प्रश्न पूछकर इसे जानते हैं), तो मैं सिंक्रोनस कोड का उपयोग करने की सलाह दूंगा। Async सभी तरह से सबसे अच्छा है; सिंक सभी तरह से दूसरा सबसे अच्छा है। सिंक-ओवर-एसिंक की अनुशंसा नहीं की जाती है।

हालांकि, ऐसी कुछ स्थितियां हैं जहां सिंक-ओवर-एसिंक आवश्यक है। विशेष रूप से, आप कॉलिंग कोड से बाध्य हैं ताकि आपको सिंक होना पड़े (और एसिंक्रनाइज़ेशन को अनुमति देने के लिए अपने कोड को फिर से सोचने या पुन: संरचना करने का बिल्कुल कोई तरीका नहीं है), और आपको एसिंक कोड को कॉल करना होगा। यह एक बहुत ही दुर्लभ स्थिति है, लेकिन यह समय-समय पर आती है।

उस स्थिति में, आपको ब्राउनफील्ड async विकास पर मेरे लेख में वर्णित हैक्स में से एक का उपयोग करना होगा, विशेष रूप से:

  • अवरुद्ध करना (उदाहरण के लिए, GetAwaiter().GetResult() )। ध्यान दें कि इससे डेडलॉक्स हो सकते हैं (जैसा कि मैंने अपने ब्लॉग पर वर्णन किया है)।
  • थ्रेड पूल थ्रेड पर कोड चलाना (उदाहरण के लिए, Task.Run(..).GetAwaiter().GetResult() )। ध्यान दें कि यह केवल तभी काम करेगा जब एसिंक्रोनस कोड थ्रेड पूल थ्रेड पर चलाया जा सकता है (यानी, यूआई या एएसपी.NET संदर्भ पर निर्भर नहीं है)।
  • नेस्टेड संदेश loops। ध्यान दें कि यह केवल तभी काम करेगा यदि एसिंक्रोनस कोड केवल एक एकल थ्रेडेड संदर्भ मानता है, एक विशिष्ट संदर्भ प्रकार नहीं (बहुत सारे UI और ASP.NET कोड एक विशिष्ट संदर्भ की अपेक्षा करते हैं)।

नेस्टेड संदेश लूप सभी हैक्स का सबसे खतरनाक है, क्योंकि यह re-entrancy । पुन: प्रवेश के बारे में तर्क करना बेहद मुश्किल है, और (आईएमओ) विंडोज़ पर अधिकांश एप्लिकेशन कीड़े का कारण है। विशेष रूप से, यदि आप यूआई थ्रेड पर हैं और आप वर्क कतार (एसिंक काम पूरा करने के लिए प्रतीक्षा कर रहे हैं) पर अवरुद्ध करते हैं, तो सीएलआर वास्तव में आपके लिए कुछ संदेश पंपिंग करता है - यह वास्तव में आपके भीतर से कुछ Win32 संदेशों को संभाल लेगा कोड ओह, और आपको पता नहीं है कि कौन से संदेश - जब क्रिस ब्रूम कहते हैं, "क्या यह जानना अच्छा नहीं होगा कि वास्तव में क्या पंप हो जाएगा? दुर्भाग्यवश, पंपिंग एक काला कला है जो प्राणघातक समझ से परे है।" , तो हमें वास्तव में जानने की कोई उम्मीद नहीं है।

इसलिए, जब आप यूआई थ्रेड पर इस तरह ब्लॉक करते हैं, तो आप परेशानी के लिए पूछ रहे हैं। एक ही लेख से एक और cbrumme उद्धरण: "समय-समय पर, कंपनी के अंदर या बाहर के ग्राहकों को पता चलता है कि हम एसटीए [यूआई थ्रेड] पर प्रबंधित अवरोधन के दौरान संदेश पंप कर रहे हैं। यह एक वैध चिंता है, क्योंकि वे जानते हैं कि यह बहुत कठिन है कोड लिखने के लिए जो पुनर्वित्त के चेहरे पर मजबूत है। "

हाँ यही है। कोड लिखना बहुत मुश्किल है जो पुनर्वित्त के चेहरे पर मजबूत है। और घोंसला संदेश लूप आपको कोड लिखने के लिए मजबूर करता है जो पुनर्वित्त के चेहरे पर मजबूत है। यही कारण है कि इस प्रश्न के लिए स्वीकृत (और सबसे ऊपर उठाया गया) जवाब अभ्यास में बेहद खतरनाक है।

यदि आप अन्य सभी विकल्पों से पूरी तरह से बाहर हैं - आप अपने कोड को फिर से डिज़ाइन नहीं कर सकते हैं, तो आप इसे एसिंक के रूप में पुन: स्थापित नहीं कर सकते - आपको अपरिवर्तनीय कॉलिंग कोड सिंक होने के लिए मजबूर किया जाता है - आप डाउनस्ट्रीम कोड को सिंक होने के लिए नहीं बदल सकते - आप ब्लॉक नहीं कर सकते - आप एसिंक कोड को एक अलग थ्रेड पर नहीं चला सकते हैं - तब केवल तभी आपको पुनर्वितरण को गले लगाने पर विचार करना चाहिए।

यदि आप स्वयं को इस कोने में पाते हैं, तो मैं WPF ऐप्स के लिए Dispatcher.PushFrame , WinForm ऐप्स के लिए एप्लिकेशन. AsyncContext.Run साथ looping, और सामान्य मामले के लिए, अपने स्वयं के AsyncContext.Run जैसे कुछ का उपयोग करने की सलाह AsyncContext.Run

मैं async / प्रतीक्षा के बारे में सीख रहा हूं, और ऐसी परिस्थिति में भाग गया जहां मुझे एक एसिंक विधि को समकालिक रूप से कॉल करने की आवश्यकता है। मैं उसे कैसे कर सकता हूँ?

Async विधि:

public async Task<Customers> GetCustomers()
{
    return await Service.GetCustomersAsync();
}

सामान्य उपयोग:

public async void GetCustomers()
{
    customerList = await GetCustomers();
}

मैंने निम्नलिखित का उपयोग करने का प्रयास किया है:

Task<Customer> task = GetCustomers();
task.Wait()

Task<Customer> task = GetCustomers();
task.RunSynchronously();

Task<Customer> task = GetCustomers();
while(task.Status != TaskStatus.RanToCompletion)

मैंने here से एक सुझाव भी आजमाया, हालांकि यह तब काम नहीं करता जब प्रेषक निलंबित राज्य में होता है।

public static void WaitWithPumping(this Task task) 
{
        if (task == null) throw new ArgumentNullException(“task”);
        var nestedFrame = new DispatcherFrame();
        task.ContinueWith(_ => nestedFrame.Continue = false);
        Dispatcher.PushFrame(nestedFrame);
        task.Wait();
}

RunSynchronously कॉल करने से अपवाद और स्टैक ट्रेस यहां दिया गया है:

System.InvalidOperationException

संदेश : RunSynchronously किसी प्रतिनिधि को असाइन किए गए कार्य पर नहीं कहा जा सकता है।

आंतरिक अपवाद : शून्य

स्रोत : mscorlib

स्टैकट्रेस :

          at System.Threading.Tasks.Task.InternalRunSynchronously(TaskScheduler scheduler)
   at System.Threading.Tasks.Task.RunSynchronously()
   at MyApplication.CustomControls.Controls.MyCustomControl.CreateAvailablePanelList() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 638
   at MyApplication.CustomControls.Controls.MyCustomControl.get_AvailablePanels() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 233
   at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>b__36(DesktopPanel panel) in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 597
   at System.Collections.Generic.List`1.ForEach(Action`1 action)
   at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>d__3b.MoveNext() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 625
   at System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClass7.<TrySetContinuationForAwait>b__1(Object state)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
   at MyApplication.App.Main() in C:\Documents and Settings\...\MyApplication\obj\Debug\App.g.cs:line 50
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

अगर मैं आपका प्रश्न सही पढ़ रहा हूं - वह कोड जो एक एसिंक विधि को सिंक्रोनस कॉल चाहता है, निलंबित प्रेषक थ्रेड पर निष्पादित हो रहा है। और आप वास्तव में सिंक्रनाइज़ रूप से उस थ्रेड को अवरुद्ध करना चाहते हैं जब तक कि एसिंक विधि पूरी नहीं हो जाती।

सी # 5 में असिंक विधियों को विधि को प्रभावी ढंग से हुड के नीचे टुकड़ों में काटकर, और एक Task लौटाकर पूरे शबांग के समग्र समापन को ट्रैक कर सकते हैं। हालांकि, कैसे कटा हुआ अप विधियां निष्पादित करने के लिए await ऑपरेटर को पारित अभिव्यक्ति के प्रकार पर निर्भर कर सकते हैं।

अधिकांश समय, आप टाइप Task की अभिव्यक्ति पर await कर await होंगे। await पैटर्न का कार्य कार्यान्वयन "स्मार्ट" है जिसमें यह SynchronizationContext कॉन्टेक्स्ट को रोकता है, जो मूल रूप से निम्न होने का कारण बनता है:

  1. यदि await में प्रवेश करने वाला थ्रेड डिस्पैचर या WinForms संदेश लूप थ्रेड पर है, तो यह सुनिश्चित करता है कि एसिंक विधि के भाग संदेश कतार के प्रसंस्करण के हिस्से के रूप में होते हैं।
  2. यदि await में प्रवेश करने वाला थ्रेड थ्रेड पूल थ्रेड पर है, तो एसिंक विधि के शेष भाग थ्रेड पूल पर कहीं भी होते हैं।

यही कारण है कि आप शायद समस्याओं में चल रहे हैं - async विधि कार्यान्वयन डिस्पैचर पर बाकी को चलाने की कोशिश कर रहा है - भले ही इसे निलंबित कर दिया गया हो।

.... समर्थन करना! ....

मुझे सवाल पूछना है, आप एक एसिंक विधि पर सिंक्रनाइज़ रूप से अवरुद्ध करने की कोशिश क्यों कर रहे हैं? ऐसा करने से इस उद्देश्य को हराया जाएगा कि विधि को अतुल्यकालिक रूप से क्यों कहा जाना चाहिए था। आम तौर पर, जब आप डिस्पैचर या यूआई विधि पर await का उपयोग शुरू करते हैं, तो आप अपना पूरा यूआई प्रवाह एसिंक चालू करना चाहेंगे। उदाहरण के लिए, यदि आपका कॉलस्टैक निम्न जैसा था:

  1. [शीर्ष] WebRequest.GetResponse ()
  2. YourCode.HelperMethod ()
  3. YourCode.AnotherMethod ()
  4. YourCode.EventHandlerMethod ()
  5. [यूआई कोड]। नलसाजी () - डब्ल्यूपीएफ या WinForms कोड
  6. [संदेश लूप] - डब्ल्यूपीएफ या विनफॉर्म संदेश लूप

फिर कोड को एसिंक का उपयोग करने के लिए परिवर्तित कर दिया गया है, तो आप आम तौर पर समाप्त हो जाएगा

  1. [शीर्ष] WebRequest.GetResponseAsync ()
  2. YourCode.HelperMethodAsync ()
  3. YourCode.AnotherMethodAsync ()
  4. YourCode.EventHandlerMethodAsync ()
  5. [यूआई कोड]। नलसाजी () - डब्ल्यूपीएफ या WinForms कोड
  6. [संदेश लूप] - डब्ल्यूपीएफ या विनफॉर्म संदेश लूप

असल में जवाब देना

उपरोक्त AsyncHelpers वर्ग वास्तव में काम करता है क्योंकि यह एक नेस्टेड संदेश पाश की तरह व्यवहार करता है, लेकिन यह डिस्पैचर पर निष्पादित करने की कोशिश करने के बजाय डिस्पैचर को अपना समांतर मैकेनिक स्थापित करता है। यह आपकी समस्या के लिए एक कामकाज है।

एक और कामकाज थ्रेडपूल थ्रेड पर अपनी एसिंक विधि निष्पादित करना है, और फिर इसे पूरा करने के लिए प्रतीक्षा करें। ऐसा करना आसान है - आप इसे निम्न स्निपेट के साथ कर सकते हैं:

var customerList = TaskEx.RunEx(GetCustomers).Result;

अंतिम एपीआई कार्य होगा। रुन (...), लेकिन सीटीपी के साथ आपको पूर्व प्रत्यय ( यहां स्पष्टीकरण ) की आवश्यकता होगी।


कार्य को सिंक्रनाइज़ करने के लिए और यूआई थ्रेड को अवरुद्ध किए बिना मुझे सबसे आसान तरीका है RunSynchronously () जैसे:

Task t = new Task(() => 
{ 
   //.... YOUR CODE ....
});
t.RunSynchronously();

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


बस एक छोटा सा नोट - यह दृष्टिकोण:

Task<Customer> task = GetCustomers();
task.Wait()

WinRT के लिए काम करता है।

मुझे समझाने दो:

private void TestMethod()
{
    Task<Customer> task = GetCustomers(); // call async method as sync and get task as result
    task.Wait(); // wait executing the method
    var customer = task.Result; // get's result.
    Debug.WriteLine(customer.Name); //print customer name
}
public class Customer
{
    public Customer()
    {
        new ManualResetEvent(false).WaitOne(TimeSpan.FromSeconds(5));//wait 5 second (long term operation)
    }
    public string Name { get; set; }
}
private Task<Customer> GetCustomers()
{
    return Task.Run(() => new Customer
    {
        Name = "MyName"
    });
}

Moreover this approach works for Windows Store solutions only!

Note: This way isn't thread safe if you call your method inside of other async method (according to comments of @Servy)


मैंने इसे कुछ बार सामना किया है, ज्यादातर यूनिट परीक्षण में या विंडोज़ सेवा विकास में। वर्तमान में मैं हमेशा इस सुविधा का उपयोग करता हूं:

        var runSync = Task.Factory.StartNew(new Func<Task>(async () =>
        {
            Trace.WriteLine("Task runSync Start");
            await TaskEx.Delay(2000); // Simulates a method that returns a task and
                                      // inside it is possible that there
                                      // async keywords or anothers tasks
            Trace.WriteLine("Task runSync Completed");
        })).Unwrap();
        Trace.WriteLine("Before runSync Wait");
        runSync.Wait();
        Trace.WriteLine("After runSync Waited");

यह आसान, आसान है और मुझे कोई समस्या नहीं थी।


यह मेरे लिए अच्छा काम कर रहा है

public static class TaskHelper
{
    public static void RunTaskSynchronously(this Task t)
    {
        var task = Task.Run(async () => await t);
        task.Wait();
    }

    public static T RunTaskSynchronously<T>(this Task<T> t)
    {
        T res = default(T);
        var task = Task.Run(async () => res = await t);
        task.Wait();
        return res;
    }
}

शेड्यूलर को सिंक्रनाइज़ करने के लिए चाल करने की कोशिश करने के बजाए, थ्रेड पूल पर कार्य को चलाने के लिए यह बहुत आसान है। इस तरह आप सुनिश्चित कर सकते हैं कि यह डेडलॉक नहीं होगा। संदर्भ स्विच के कारण प्रदर्शन प्रभावित होता है।

Task<MyResult> DoSomethingAsync() { ... }

// Starts the asynchronous task on a thread-pool thread.
// Returns a proxy to the original task.
Task<MyResult> task = Task.Run(() => DoSomethingAsync());

// Will block until the task is completed...
MyResult result = task.Result; 

सलाह दीजिये कि यह जवाब तीन साल पुराना है। मैंने इसे नेट 4.0 के साथ अनुभव पर आधारित लिखा है, और 4.5 के साथ बहुत कम विशेष रूप से async-await साथ। आम तौर पर यह एक अच्छा सरल समाधान है, लेकिन यह कभी-कभी चीजों को तोड़ देता है। टिप्पणियों में चर्चा पढ़ें।

नेट 4.5

बस इसका इस्तेमाल करें:

// For Task<T>: will block until the task is completed...
var result = task.Result; 

// For Task (not Task<T>): will block until the task is completed...
task2.RunSynchronously();

देखें: TaskAwaiter , Task.Result TaskAwaiter , Task.ResultTask.RunSynchronously

नेट 4.0

इसे इस्तेमाल करो:

var x = (IAsyncResult)task;
task.Start();

x.AsyncWaitHandle.WaitOne();

...या यह:

task.Start();
task.Wait();

In your code, your first wait for task to execute but you haven't started it so it waits indefinitely. इसे इस्तेमाल करे:

Task<Customer> task = GetCustomers();
task.RunSynchronously();

संपादित करें:

You say that you get an exception. Please post more details, including stack trace.
Mono contains the following test case:

[Test]
public void ExecuteSynchronouslyTest ()
{
        var val = 0;
        Task t = new Task (() => { Thread.Sleep (100); val = 1; });
        t.RunSynchronously ();

        Assert.AreEqual (1, val);
}

Check if this works for you. If it does not, though very unlikely, you might have some odd build of Async CTP. If it does work, you might want to examine what exactly the compiler generates and how Task instantiation is different from this sample.

Edit #2:

I checked with Reflector that the exception you described occurs when m_action is null . This is kinda odd, but I'm no expert on Async CTP. As I said, you should decompile your code and see how exactly Task is being instantiated any how come its m_action is null .

PS What's the deal with the occasional downvotes? Care to elaborate?


On wp8:

Wrap it:

Task GetCustomersSynchronously()
{
    Task t = new Task(async () =>
    {
        myCustomers = await GetCustomers();
    }
    t.RunSynchronously();
}

Call it:

GetCustomersSynchronously();

Simply calling .Result; or .Wait() is a risk for deadlocks as many have said in comments. Since most of us like oneliners you can use these for .Net 4.5<

Acquiring a value via an async method:

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

Syncronously calling an async method

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

No deadlock issues will occur due to the use of Task.Run .

स्रोत:

https://.com/a/32429753/3850405


This answer is designed for anyone who is using WPF for .NET 4.5.

If you attempt to execute Task.Run() on the GUI thread, then task.Wait() will hang indefinitely, if you do not have the async keyword in your function definition.

This extension method solves the problem by checking to see if we are on the GUI thread, and if so, running the task on the WPF dispatcher thread.

This class can act as the glue between the async/await world and the non-async/await world, in situations where it is unavoidable, such as MVVM properties or dependencies on other APIs that do not use async/await.

/// <summary>
///     Intent: runs an async/await task synchronously. Designed for use with WPF.
///     Normally, under WPF, if task.Wait() is executed on the GUI thread without async
///     in the function signature, it will hang with a threading deadlock, this class 
///     solves that problem.
/// </summary>
public static class TaskHelper
{
    public static void MyRunTaskSynchronously(this Task task)
    {
        if (MyIfWpfDispatcherThread)
        {
            var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { await task; });
            result.Wait();
            if (result.Status != DispatcherOperationStatus.Completed)
            {
                throw new Exception("Error E99213. Task did not run to completion.");
            }
        }
        else
        {
            task.Wait();
            if (task.Status != TaskStatus.RanToCompletion)
            {
                throw new Exception("Error E33213. Task did not run to completion.");
            }
        }
    }

    public static T MyRunTaskSynchronously<T>(this Task<T> task)
    {       
        if (MyIfWpfDispatcherThread)
        {
            T res = default(T);
            var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { res = await task; });
            result.Wait();
            if (result.Status != DispatcherOperationStatus.Completed)
            {
                throw new Exception("Error E89213. Task did not run to completion.");
            }
            return res;
        }
        else
        {
            T res = default(T);
            var result = Task.Run(async () => res = await task);
            result.Wait();
            if (result.Status != TaskStatus.RanToCompletion)
            {
                throw new Exception("Error E12823. Task did not run to completion.");
            }
            return res;
        }
    }

    /// <summary>
    ///     If the task is running on the WPF dispatcher thread.
    /// </summary>
    public static bool MyIfWpfDispatcherThread
    {
        get
        {
            return Application.Current.Dispatcher.CheckAccess();
        }
    }
}

Why not create a call like:

Service.GetCustomers();

that isn't async.



    private int GetSync()
    {
        try
        {
            ManualResetEvent mre = new ManualResetEvent(false);
            int result = null;

            Parallel.Invoke(async () =>
            {
                result = await SomeCalcAsync(5+5);
                mre.Set();
            });

            mre.WaitOne();
            return result;
        }
        catch (Exception)
        {
            return null;
        }
    }