Jump to content

Have you seen the parallel keywords that Microsoft has been introducing into the other languages lately?


Daklu

Recommended Posts

Have you guys seen the parallel keywords that Microsoft has been introducing into the other languages lately? Everything needs to be parallel, but procedural programming is a dead end. There is only so far you can go with compiler analysis of procedural code and manual control of mutexes before you hit a wall and flat out say, "No, I need a system that is designed for multicore from the outset."

Microsoft's new Task-based Asynchronous Pattern.

C# async and await keywords in Visual Studio 2011.

I agree. Just last weekend I was discussing those keywords with someone who writes MSDN documentation. I left with the distinct impression that it's much harder to reason about the possible code sequences (and potential bugs) when there's no data flow to control it.

An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.

One thing that wasn't clear to me was what are valid conditions for the async method to resume? Does execution jump out of whatever is currently executing to finish the async method? The person I was talking to didn't know the answer...

The other thing about these new keywords I didn't understand until ~45 minutes into our discussion is they are a way to bring asynchronous behavior to a single-threaded application. They are an improvement, but they don't really help with multithreading at all.

Link to comment

Async programming does not necessarily imply multithreading but it can help. Async just says that this method is something that someone can call await on. Await says I want to make my thread available to run other code until I'm told to continue, then run the rest of my code. Viewed from the context of a single thread, this is really just cooperative multitasking. It is the same thing LabVIEW's scheduler does for the UI thread.

The key to turning this from cooperative multitasking into multithreading is that await can be called on things from other threads. The easiest way to use await for multithreading is with Task. Tasks run in the thread pool, you can await any task and you don't consume your thread while in the await.

When writing UI code in .NET, most of your work is done in event handlers. The user presses a button and you do something. If the thing you do is a calculation that takes 5 seconds and you do it directly in the handler, your UI is frozen for those 5 seconds. If you make that async, it still freezes your UI for 5 seconds because it is still doing all that calculation in the UI thread. So you want to do the calculation in the thread pool. However UI objects can only be modified from the UI thread, so you can't update your display at the end of the calculation from the thread pool. What you need to do is start the calculation in the thread pool from your handler, then schedule the update back to the UI thread when the thread pool finishes the calculation. Writing this code is made simpler with async and await. You simply mark your handler as async, start the calculation using the Task class, await the task, then update your UI.

The closest analogue in LabVIEW is the event structure. If you need to do something lengthy and you want other events to be handled while it runs, you have to somehow make that execution happen outside the event frame. There are various approaches to that with the latest being the async call by ref. In some respects this still isn't as smooth as what MS has done with async/await, but it is a little different for a dataflow language. Are there other presentations that you think would work well for async event handling in LabVIEW?

Link to comment
  • 3 weeks later...

(Somehow I missed this response earlier. I also don't know what happened to the original message... maybe AQ deleted it?)

I appreciate the reply. Figuring out the terminology is often one of the biggest hurdles to learning different approaches. I have written C# programs and understand the certain parts of the .Net framework, but I'm not nearly as fluent in it as I wish I was. (In particular the whole UI / delegate / event system still puzzles me.) Your explanation helps.

Using Tasks for concurrent programming is still a little confusing. I'll use your example of a button event handler that creates a task to do the 5 second calculation, launches it, and await on it. As I understand it, the state of the local variables in the event handler are remembered and execution "jumps" out of that method to continue processing UI code. When the task finishes the UI execution jumps back into the event handler at the await call, restores the values of the local variables, and continues processing the method from that point. Is that mostly correct?

What happens if, immediately after awaiting on the 5 second task, I press another button that starts a 10 second calculation in the UI thread? Is my UI calculation interrupted to finish the remaining statements in the the first event handler? I guess I'm wondering how the remaining code in a method following an await is scheduled relative to code currently executing in the UI thread. Does the Task response interrupt the UI thread or is the response just added to the event queue to be processed in order?

In Labview I primarily use queues and messages to transfer data between concurrent code. The points at which my parent loop will actually process the response are clearly shown by the dequeue node. I may not know exactly when the response message will be processed relative to other messages, but I can easily see it won't interrupt any other messages being handled. I don't see that clarity in the .Net model. Maybe it's a inherent rule experienced C# developers know about?

In some respects this still isn't as smooth as what MS has done with async/await, but it is a little different for a dataflow language.

Yeah, I can see how the automatic jumping out and jumping in to a method would make it easier to write certain kinds of methods. At the same time, jumping out of an event frame before it has finished and jumping back in to continue from where it left off is a huge dataflow violation and we'd all freak out the first time we saw it happen. :lol:

I have admit, the more I think about it the more I kind of like it. Suppose I want to execute lengthy calculations A, B, and C in series when a button is pressed. In really bad pseudocode, using await the event handler would look something like this:


MyMethod handles btn.OnClick

...

start TaskA;

await TaskA;

msg.text = "TaskA finished";

start TaskB;

await TaskB;

msg.text = "TaskB finished";

start TaskC;

await TaskC;

msg.text = "TaskC finished";

...

[/CODE]

It's very clear from looking at the code that each of the tasks will be executed in sequence from this one button click. In G I can't do that. I need to create separate message handlers for when each of the tasks is finished and chain them together in code. The bad pseudocode textual equivalent would be...

[CODE] MyMethod handles btn.OnClick start TaskA; End TaskAFinished handles TaskA.finished msg.text = "TaskA finished"; start TaskB; End TaskBFinished handles TaskB.finished msg.text = "TaskB finished"; start TaskC; End TaskCFinished handles TaskC.finished msg.text = "TaskC finished"; End [/CODE]

This is clearly not as easy to understand as the implementation using await. Furthermore, this code permanently establishes the sequential nature of the tasks. I can't start task B and get a response without also invoking task C. There are way to work around that within the restrictions imposed by data flow (like using UI states to implement different responses to the same message,) but I haven't found anything as simple, clear, and robust as what the task based await approach appears to give C# developers. In some respects await is like an abstracted, [s]generic[/s] anonymous event handler temporarily bound to the Task. You get the same behavior without all the messy delegates and event handling code.

Are there other presentations that you think would work well for async event handling in LabVIEW?

None I can think of off the top of my head, but now that I understand the task-based approach better (assuming my descriptions above are correct) I'll certainly be thinking about it. Message sequences in Labview are difficult to infer simply by looking at code and I've struggled with how to overcome that for a while.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.