locked
Can I use asynchronous API synchronously? RRS feed

  • Question

  • I'm porting class library with synchronous file IO to Metro. I start from the asynchronous API in Windows Runtime with async/await, and try to modify it with Task.Wait() to wait synchronously till the task complete. Finally I suppose I can remove async keyword in order to make the function callable from any legacy synchronous method.

    Following code illustrates the problem I met on the way. As in the comment bellow, I get error dialog with message "Reentrancy detected in XAML application". How can I treat the error?

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
    	Task<StorageFile> createTask = ApplicationData.Current.LocalFolder.CreateFileAsync("output.txt").StartAsTask<StorageFile>();
    	createTask.Wait(); // complete and file is created
    	Task<IRandomAccessStream> openTask = createTask.Result.OpenAsync(FileAccessMode.ReadWrite).StartAsTask<IRandomAccessStream>();
    	openTask.Wait(); // complete but cause crash below
    	IOutputStream outputStream = openTask.Result.GetOutputStreamAt(0);
    	DataWriter writer = new DataWriter(outputStream);
    	writer.WriteString("this is a test!");
    	await writer.StoreAsync(); // crash with "Reentrancy detected in XAML application."
    	await outputStream.FlushAsync();
    }


    Monday, February 20, 2012 7:02 AM

Answers

  • Finally I wrapped async method by lambda and invoke it by TaskFactory.StartNew(), then wait returned task.

    Task task = Task.Factory.StartNew(async () => { ... });
    task.Wait()

    Thank you for the answers. I'll consider changing library method to be async, in other cases it is applicable

    Tuesday, February 28, 2012 5:34 AM
  • Hello,

    Even if there is a way, you shouldn't try to avoid asynchronous execution. It will impact on the execution time and prevent your application to use all the resources offered by the hardware. Even if that means that you will have to change your application in order to access IO asynchronously it is well worth it. Accessing the storage is relatively slow, and you shouldn't do it in the UI thread, as it could make your application look unresponsive, which is something you want to avoid in order to offer a better user experience.

    Thank You,

    Joseph

    • Proposed as answer by Joseph Viola Monday, February 20, 2012 3:05 PM
    • Marked as answer by Yoichi Nakayama Tuesday, February 28, 2012 5:35 AM
    Monday, February 20, 2012 3:05 PM

All replies

  • Don't work around the async. Embrace it instead of trying to force synchronicity into it. Things are async for a VERY good reason.
    Monday, February 20, 2012 7:41 AM
  • One option is to change the legacy code to use await. If you need to maintain compatibility with sl you can use the async ctp.
    Monday, February 20, 2012 9:12 AM
  • Hello,

    Even if there is a way, you shouldn't try to avoid asynchronous execution. It will impact on the execution time and prevent your application to use all the resources offered by the hardware. Even if that means that you will have to change your application in order to access IO asynchronously it is well worth it. Accessing the storage is relatively slow, and you shouldn't do it in the UI thread, as it could make your application look unresponsive, which is something you want to avoid in order to offer a better user experience.

    Thank You,

    Joseph

    • Proposed as answer by Joseph Viola Monday, February 20, 2012 3:05 PM
    • Marked as answer by Yoichi Nakayama Tuesday, February 28, 2012 5:35 AM
    Monday, February 20, 2012 3:05 PM
  • The library is used in multi-thread application, and functions are called from non-UI threads. (Example code is just a test code to check portability of the library functions to Metro.)

    Tuesday, February 21, 2012 11:41 AM
  • Finally I wrapped async method by lambda and invoke it by TaskFactory.StartNew(), then wait returned task.

    Task task = Task.Factory.StartNew(async () => { ... });
    task.Wait()

    Thank you for the answers. I'll consider changing library method to be async, in other cases it is applicable

    Tuesday, February 28, 2012 5:34 AM
  • I understand the need for asynchronicity in UI threads, but hardly in 'worker' threads,
    and I am NOT ready to blindly obey to MS, and certainly not after the damage caused by their communication
    to the .Net community during the last 18 months.

    I find difficult to accept to be forced to use async only APIs even for low level operations such as opening an reading a file.
    Given that MS is so LATE in the mobile field, I would appreciate them to make our developer life as easy and smooth as possible,
    and avoid to impose us unneeded breaking changes and additionalt inconsistencies: do not force us to rebuild our existing code
    so as to make it entirely async: I have already invested a lot effort to make it very UI friendly, in a manner applying equally to WPF, SL, WP7,
    MonoTouch, MonoMac, MonoDroid!

    As far as I know, iOS does not force such paradigm shift, which doesn't prevent the iPad/iPhone apps from being very fluid,
    why shoud it be necessary for Metro?


    Tuesday, March 6, 2012 5:50 PM
  • I've also been having issues, specifically with asyncs inside asyncs. If I'm already in a background thread, sometimes I want everything there to execute synchronously, just for ease of coding. Instead I'm creating these little void stub methods, and it seems a bit sloppy to me.

    I know the chances of getting this behavior changed are slim to none, but it would be nice if there was the opposite of the await keyword that forced an awaitable method to execute synchronously.


    No matter where you go, there you are. -Buckaroo Banzai

    Tuesday, March 6, 2012 5:56 PM
  • I've also been having issues, specifically with asyncs inside asyncs. If I'm already in a background thread, sometimes I want everything there to execute synchronously, just for ease of coding. Instead I'm creating these little void stub methods, and it seems a bit sloppy to me.

    What stub methods do you need to create?  I've found switching to async methods *greatly* nicer than the old begin/end pattern and every bit as clean as non-async methods.

    --randy

    Tuesday, March 6, 2012 7:29 PM
  • I am just curious: please explain what is the benefit of using async methods in a worker thread,
    and of even not being given the choice between the sync and async versions of such core functionalities
    as those involved in a simple file access?


    Wednesday, March 7, 2012 3:31 PM
  • I am just curious: please explain what is the benefit of using async methods in a worker thread,
    and of even not being given the choice between the sync and async versions of such core functionalities
    as those involved in a simple file access?

    (Please be aware that I am not on any of the teams involved, so am speaking simply as another app developer here)

    There's a few advantages:

    1. Threads are a limited resource.  While they aren't particularly expensive, it's definitely better to conserve them.
    2. You don't have to worry about accidentally calling a sync method on the UI thread.  This can especially be a concern when a sync call might be hidden inside third-party helper libraries that you are using.  Having only the async APIs won't entirely protect you -- you still have to watch out for CPU-expensive operations -- but it's a significant help.
    3. Less APIs for everyone to learn and program with.
    4. You are forced to learn to use the async APIs, so that you can use them when they are definitely needed.
    5. Fewer core APIs for the platform team to implement, document and test means more time for them to implement entirely new capabilities.

    Thanks,

    --randy

    Wednesday, March 7, 2012 4:07 PM
  • <<(Please be aware that I am not on any of the teams involved, so am speaking simply as another app developer here)
    Thanks for your comments.

    Worker threads make easy to separate the code implementing a job  from the fact that this job as to be done asynchronously
    regarding the UI or not: since those aspects can be decoupled they have to be.

    The paradigm imposed by WinRT is way too intrusive, it adds even more fragmentation to an already fragmented enough .Net landscape.
    iOS does not impose such a shift. 

    I should at least be given the choice to use the standard BCL or not.

    In order to prevent the WinRT applications from freezing, it would be very easy to prevent some of the potentially lenghty APIs
    exposed by the BCL from being invoked from the UI thread, in the same way the WinRT UI elements cannot be manipulated from a non UI thread.

    Thursday, March 8, 2012 5:31 PM
  • this async fileIO is very dificult , unusable and slowly, need better approach,

    i probably with Lambda expression , but i have a problem, smart pointer in lamda parameter not possible, WTF?

    		void ReadDataAsync(Platform::String^ filename,function<void (byte*,int)> callback)
    		{
    			Concurrency::task<Windows::Storage::StorageFile^>(m_location->GetFileAsync(filename)).then([=](Windows::Storage::StorageFile^ file)
    			{
    				return Windows::Storage::FileIO::ReadBufferAsync(file);
    			}).then([=](Windows::Storage::Streams::IBuffer^ buffer)
    			{
    				Platform::Array<byte>^ fileData = ref new Platform::Array<byte>(buffer->Length);
    				Windows::Storage::Streams::DataReader::FromBuffer(buffer)->ReadBytes(fileData);
    				
    				byte* data=new byte[buffer->Length];
    				for(int i=0;i<buffer->Length;i++) data[i]=fileData[i];
    				callback(data,buffer->Length);
    			});
    		}
    

    Wednesday, April 4, 2012 8:37 PM
  • I am with Philippe here.  I was astounded to learn only async methods are available. 

    Maybe Microsoft is trying to say: some app developers have been designing poor thread models in the past, so we are going to impose one on you.  That is equivalent to saying: if you want to design your own thread model, don't use our APIs.

    Friday, August 31, 2012 11:08 PM
  • Yeah, I don't get it.  I have a model that uses file, database, or WCF services that I want to use in versions of my app based on ASP .NET, Silverlight, WP8, WinRT, WPF, Android (via Xamarin Monodroid), and IOS (via Xamarin), but using the async model seems to require propagating the async keyword throughout all the function using the async IO.  I was perfectly fine creating threads in just a few places to do the synchronous stuff.  What am I going to do since Xamarin doesn't support the new async stuff?

    Friday, February 15, 2013 3:39 PM
  • Yoichi,

    Could you expand on this (how to use lambda to do async stuff synchronously)?  I.e. what's in the ... section?

    Thanks.

    -John

    Friday, February 15, 2013 3:49 PM
  • Some times you need to access some API synchronously inside asynchronous functions...

    Examples: multiple files loading during logon process

    Tuesday, November 4, 2014 4:03 AM