How to use Async and Await ?

Using (or providing) Microsoft.NET Classes

Re: How to use Async and Await ?

Postby PGilbert on Wed Jan 06, 2016 1:19 pm

Hello Thomas and Vince, making the .Wait longer does not work for me, I still have the value error when trying to get the Exception. But if I put a ⎕DL 20 after the task has finished it is working:

      :If 0=⎕TSYNC task.Wait&(5000) ⍝ Wait no more than 5 seconds for the task to complete
⎕←'Failure'
⎕DL 20 ⍝ Delay before asking the Exception
task.Exception.GetBaseException.Message
:Else
⎕←'Success'
:End


I still don't understand why there is a need to wait 20 seconds to get the Exception. You have an Exception or you don't have an Exception when the task time-out on the 5 seconds. The exception does not appear by itself 20 seconds later or does it ?
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to use Async and Await ?

Postby Tomas Gustafsson on Wed Jan 06, 2016 7:46 pm

PGilbert wrote:The exception does not appear by itself 20 seconds later or does it ?

Indeed it does and imho this is how it should behave. Since, as your code executes ⎕EXCEPTION, it is the very moment it asks .net for it. And ofc, as it's all async action, whatever .net has handy for a query of exception may change as often as it wants. Who knows if it even has many different shapes during the .Wait? Similarly, .net most likely didn't create the content of ⎕EXCEPTION exactly 20 secs later, it appeared between 15 and 20 secs after initial call. I tested, 15 secs did the errors you intially mentioned while 20 secs gave a valid and well-formed exception msg. I guess we have different defaults. I have Win7. Also you can change the timeout for tcpip actions, maybe test with that too?

I guess one should not even try with a fixed wait time, but instead react (and query exception) whenever the async call decides to drop out. Because if this was C# code, the async call would do a "kind of" hang there (while still letting execution go on). And that "kind of" hang would by itself complete at some point in time. And at *that* point, ⎕EXCEPTION would most likely hold something, at least if there was a failure -> a reason to ask for the exception msg.
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

Re: How to use Async and Await ?

Postby PGilbert on Thu Jan 07, 2016 2:10 am

Looks like Tomas (and Vince) that you are correct. From further reading I have convince myself that there is a time-out to connect that surprisingly cannot be changed (must be around 20 seconds). If the task to ConnectAsync terminates before say the 20 seconds, there will be no error available yet because the underlying socket is still trying to connect on the default time-out of 20 seconds. So it is not possible to get that error before 20 seconds. If you do a synchronous connect there will be always a delay of 20 seconds for that type of error. At least with ConnectAsync we can decide of the time-out that will terminate the task that is trying to connect but that is all.
What is missing also in my code is to do a tcp.Close in the error section to close the socket.

Thanks to all for your time and patience.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to use Async and Await ?

Postby JohnD|Dyalog on Thu Jan 07, 2016 9:22 am

Hello Pierre,

Yes I think that's correct. The underlying system is still trying to connect after Wait has returned.

As you say, there seems to be a built in timeout, which cannot be set, however this thread:

http://stackoverflow.com/questions/9732713/how-do-i-set-a-timeout-of-socket-connectasync

suggests workarounds, which you may, or may not, want to consider.

Best Regards
John Daintree.
User avatar
JohnD|Dyalog
 
Posts: 74
Joined: Wed Oct 01, 2008 9:35 am

Re: How to use Async and Await ?

Postby PGilbert on Sun Jan 10, 2016 1:57 pm

For those interested in TCP/IP, UDP/IP and Serial communication, I contributed three classes to the Wiki (TCP , UDP ,COM) that are doing just that and are using the methods WriteAsync and ReadAsync to make the communication Asynchronous. Thanks everyone that helped me on this thread to complete this project.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to use Async and Await ?

Postby Tomas Gustafsson on Sun Jan 10, 2016 9:58 pm

Excellent, Pierre, thx for uploading!

I use the async serial comm as well, to send out NMEA 0183-packages from the simulator. That way i can allow a user to connect additional nav hardware and be able to see the data for the own vessel in whatever external electonics he/she connects. Atm. i send only a few packages, of which one looks typically like this:

      '$GPRMC,160504.00,A,6008.812841,N,02458.795638,E,02.183,235.973,240613,,,A*59',⎕TC[3 2]

The code builds up the package, then adds a checksum and pushes out asynchronously:

      check←{a←≠⍀↑(⌽8,⍴⍵)⍴11 ⎕DR ⍵ ⋄ '0123456789ABCDEF'[1+,83 ⎕DR 2 ¯8↑2 4⍴a[⍴⍵;]]}p   ⍝ XOR checksum, into 2 hex chars
{}#.SERIAL.STREAMS[iPort].WriteAsync(⊂83 ⎕DR a),0,⍴a←'$',p,'*',check,⎕TC[3 2]

That's it. Heartbeats by a que system, to for example once per second. No waiting for incoming, and most relevantly: No hang (we are in a game loop, would freeze the action). Calling this pkg build function and sending the result has practically no impact at all - it happens in milli- or microseconds! Thanks again to APL for being faster than the eye with small data!

Serial ports are tricky, much trickier than IP comm. They may behave badly, lock the system, hang, be slow, incompatible or hard to configure. But once the settings are correct, it's a go. One additional thing to perhaps also mention in the wiki article could be how to mechanically manage the port. Ie., computers no longer have 9/25-pin serial ports, as we know. So what you do is go to the IT shop and buy a USB<->RS232-adapter. Windows will smootly install it's driver, and after that you have the place to plug in a 9-pin serial cable. The price of an adapter is typically 20-30 euros here.

Re. the USB part, i'd however object against your logic. You use a

      :If ⎕TSYNC{task.Wait ⍵}&(_PortTimeOut)

but the whole point with async is to NOT hang and wait. Even if this happens in a separate APL thread, imho one shouldn't synchronize inside that thread. UDP, by nature, has absolutely no synchronisation. Packets shall go and may come in at any point in time, and no assumptions can exist. Hence i'd rather propose doing it with the callback logic i posted earlier. Coupling Send and Receive can ofc work in certain conditions but is more of a special case. Also to note is that a UDP packet may be big and hence segmented, plus that UDP packets can arrive in unexpected, "wrong" order.
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

Re: How to use Async and Await ?

Postby PGilbert on Sun Jan 10, 2016 11:16 pm

Thanks Tomas for sharing your comments. We use APL to do process control. We are using TCP/IP, UDP/IP and Serial communication for that. Personally I like UDP/IP since we communicate only small data packets on private network but for larger data packets it is not appropriate like you said. TCP/IP is quite more work to program to recuperate gracefully if there is a communication problem but it is the best choice for large data transfer.
When I began reading in the .Net literature about asynchronous TCP, UDP and Serial communication there is examples that are doing like you do that is more 'event' driven. But there is always a comment from a user that is correcting those examples saying that we should use the new C# 'await' and 'async' keywords instead hence my question on the forum and using ReadAsync and WriteAsync with a Task<>. This is the closest APL equivalent that I have found.
I am just a chemical engineer doing APL for process control and I don't have the qualification to comment on what is better or not for asynchronous programming but on a preliminary basis ReadAsync and WriteAsync with a Task<> is doing what we need and the programming of it is quite simple (the classes have been tested in our laboratory but not in real life yet).
Thanks for your comments I will keep them in mind if we are starting to have problems. If anybody else using those classes is having problems (or success) please let us know on this thread so we can decide what to do with those classes (keep them or rewrite them with 'events' a la Tomas).
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to use Async and Await ?

Postby PGilbert on Mon Jan 11, 2016 12:47 pm

For those that would like to experiment, I have contributed the Dyalog class HTTP on the Wiki. It is using the Microsoft class HttpClient. It allows to do an asynchronous GET request using the method GetByteArrayAsync that is not event driven and asynchronous. Please let us know if it is behaving well (or bad) in your application so that we can decide if this way of doing asynchronous call is behaving well or we should use the 'event' driven way instead.

Thanks in advance for your time in doing this little experiment.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

Re: How to use Async and Await ?

Postby Tomas Gustafsson on Mon Jan 11, 2016 4:00 pm

I see your point. Specifically to notice is i believe you practice slower and more controlled UDP communication, while for my part it is about game multiplaying. The packets leave at a dense rate, some require Ack's, some do not. There are multiple peers/endpoints to send to and receive from, so there cannot be any blocking or waiting, AND it is thread 0 who sends. Instead there are ques, tasks, housekeeping tables. Some replies may intentioally be delayed; think of it as an order with long delivery time.

Perhaps i could encourage to have strict id's in the data packets (eg. rolling packet numbering), to cater for a situation where you actually get the *previous* requests reply as incoming, while waiting for the current requests one. Same if you have multiple peers... if endpoint B replies while you are waiting for endpoint A:s reply, then you have the wrong reply. Because UDP is not bi-directional, as you noted - each transmission, regardless of direction, is a "new" one that is completely unaware of what has happened in the world earlier. The ReceiveAsync will accept (and terminate on) ANY incoming UDP data, not in particular on a response to the data that was just sent in the same function! So there is a bit of danger involved, just kindly wanted you to be aware of that.
Tomas Gustafsson
 
Posts: 101
Joined: Mon Sep 19, 2011 6:43 pm

Re: How to use Async and Await ?

Postby PGilbert on Mon Jan 11, 2016 5:13 pm

Hello Tomas, you are correct for the UDP/IP communication you need to include what I call a 'transaction label' that is a random number in the Send message and it should be the same in the Receive message otherwise it is not the right packet that you received (this is already part of the industrial communication protocol that we use). Our pace of communication is steady but always one at a time and we wait for the answer of the packet we just sent. If there is a checksum error or wrong 'transaction label' we re-Send the packet. And we do all this on a private Ethernet segment that is removing all the traffic that should not be there. This is the easy case for UDP/IP, what you are doing seems to be quite different.

We expect to have the GUI on the main thread and the communication (TCP, UDP and serial) on another thread so the GUI stays responsive, and even so the communication on the second thread will be asynchronous (so the blocking will be on a third thread). From your answer it seems that you do every thing on one thread which is quite a feast to do (hence the callback approach to asynchronous).

I have just contributed on the Wiki the namespace MODBUS that is a partial implementation of the MODBUS serial protocol that is used widely in the industry to communicate between computers and machines. You can see that there is a lot of error checking before the answer is accepted.
User avatar
PGilbert
 
Posts: 436
Joined: Sun Dec 13, 2009 8:46 pm
Location: Montréal, Québec, Canada

PreviousNext

Return to Microsoft.NET

Who is online

Users browsing this forum: No registered users and 1 guest