Welcome, Guest
Username: Password: Remember me

TOPIC:

Async question 01 Mar 2023 13:53 #25446

  • wriedmann
  • wriedmann's Avatar
  • Topic Author


  • Posts: 3367
  • Hi,

    I have the following code:
    async method _Connect( cHostName as string, cUserName as string, cPassword as string ) as Task<logic>
    local lReturn			as logic
    local oTask				as Task
    
    _oClient := AsyncFtpClient{ cHostName, cUserName, cPassword }
    oTask := _oClient:Connect()
    await oTask
    lReturn := _oClient:IsConnected
    
    return lReturn

    To be able to use the "await" keyword I need to flag the method as async.
    If I understand that correctly, this method returns only when the task is finished.

    But when I call that method from another one
    public method Connect( cHostName as string, cUserName as string, cPassword as string ) as logic
    local lReturn as logic
    
    self:_Connect( cHostName, cUserName, cPassword )
    lReturn					:= _oClient:IsConnected
    
    return lReturn
    the compiler gives me the warning
    warning XS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

    Where is my error/misunderstanding?

    Thank you very much!

    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 14:49 #25448

    • SHirsch
    • SHirsch's Avatar


  • Posts: 279
  • Hi Wolfgang,

    change to return value just to LOGIC.

    Stefan

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 14:54 #25449

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Stefan,
    thank you for your answer.
    Unfortunately this does not work:
    error XS1983: The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 15:26 #25450

    • SHirsch
    • SHirsch's Avatar


  • Posts: 279
  • Hi Wolfgang

    since you are not using the return value you can set the return type to VOID.
    You are using
    lReturn := _oClient:IsConnected

    Otherwise you should have used
    lReturn := await oTask

    Stefan

    Please Log in or Create an account to join the conversation.

    Last edit: by SHirsch.

    Async question 01 Mar 2023 15:31 #25451

    • SHirsch
    • SHirsch's Avatar


  • Posts: 279
  • maybe you can also change your code
    method _Connect( cHostName as string, cUserName as string, cPassword as string ) as logic
    local lReturn			as logic
    local oTask				as Task
    
    _oClient := AsyncFtpClient{ cHostName, cUserName, cPassword }
    oTask := _oClient:Connect()
    oTask:Wait()
    lReturn := _oClient:IsConnected
    return lReturn

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 15:53 #25452

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Stefan,

    when the return type is void, the compiler warning is gone. So I have a first solution.....

    But when calling Wait() on the task, the task is not started, but waits.
    I have now tried to call RunSynchronously() on the task, but that gives an exception:
    RunSynchronously kann nicht für eine Aufgabe aufgerufen werden, die nicht an einen Delegat gebunden ist, wie beispielsweise eine Aufgabe, die von einer asynchronen Methode zurückgegeben wird.

    So I will solve with a void return value and store the return value in a property of my main object.
    I have also tried with an out or ref parameter, but that does not works, as out and ref parameters are not permitted on async methods.

    Thank you again - I have my solution now.

    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 15:54 #25453

    • fxm
    • fxm's Avatar


  • Posts: 52
  • public method Connect( cHostName as string, cUserName as string, cPassword as string ) as logic
    local lReturn as logic
    
    self:_Connect( cHostName, cUserName, cPassword )
    lReturn					:= _oClient:IsConnected
    
    return lReturn

    One solution would be to get the result of the call to _Connect
    public method Connect( cHostName as string, cUserName as string, cPassword as string ) as logic
    local lReturn as logic
    local lConnectResult as logic
    
    lConnectResult := self:_Connect( cHostName, cUserName, cPassword ):Result
    lReturn					:= _oClient:IsConnected
    
    return lReturn

    or probably just
    public method Connect( cHostName as string, cUserName as string, cPassword as string ) as logic
    local lReturn as logic
    
    lReturn := self:_Connect( cHostName, cUserName, cPassword ):Result
    
    return lReturn

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 15:59 #25454

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Fergus,
    the problem stays in the fact that the async method cannot return anything other than a void or task value.
    If I can store the result in another place my code compiles without warning or error.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 16:38 #25455

    • fxm
    • fxm's Avatar


  • Posts: 52
  • Hi Fergus,
    the problem stays in the fact that the async method cannot return anything other than a void or task value.
    If I can store the result in another place my code compiles without warning or error.
    Wolfgang

    I think I must have missed the point. In any case, this code compiles without warnings..
    USING System
    USING System.Collections.Generic
    USING System.Linq
    USING System.Text
    using System.Threading.Tasks
    
    FUNCTION Start() AS VOID STRICT
        
        Console.WriteLine("Hello World!")
    
        LOCAL t AS Test
        t := Test{}
        t:Connect()
        
        Console.ReadKey()
    
    CLASS Test
    
    ASYNC METHOD _Connect() AS Task<LOGIC>
    
    AWAIT Task.Delay(1000)
    
    RETURN TRUE
    
    METHOD Connect AS LOGIC
    
    LOCAL lReturn AS LOGIC 
    
    lReturn := SELF:_Connect():Result
    
    RETURN lReturn
    
    END CLASS
    

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 16:57 #25457

    • HansjoergP
    • HansjoergP's Avatar


  • Posts: 77
  • Your call self:_Connect needs an await. If you need an synchronous call you can use
    self:_Connect( cHostName, cUserName, cPassword ).Result
    With the Result Call you have to be carefull, because in some situation it can result in an dead lock

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 17:06 #25458

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Hansjörg,

    Your call self:_Connect needs an await. If you need an synchronous call you can use

    but I have the await already inside the _Connect() method.... so this method should wait until the task (_oClient:Connect()) is finished.
    If I add another await statement I need to step that up to the top level. After all, one of the methods need to be called by a VO program over the COM interface.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 17:39 #25459

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Hansjörg,
    you are right: the await keyword does not stops the execution on the main thread until the task completes, but returns immediatly to the caller.
    That is not what I need.
    The Connect() call now works, but another call (ListDirectory) does not goes over the await line, but blocks there.

    Really, I feel I'm too stupid for this - maybe I should leave programming to real professionals.

    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 17:46 #25460

    • Chris
    • Chris's Avatar


  • Posts: 3984
  • Hi Wolfgang,

    I'll join you in that, I never, ever understood the ASYNC/AWAIT concept :)
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 17:55 #25462

    • leon-ts
    • leon-ts's Avatar


  • Posts: 280
  • Hello Wolfgang,

    To be able to use the "await" keyword I need to flag the method as async.
    If I understand that correctly, this method returns only when the task is finished.

    No! The AWAIT statement does not wait for the operation to complete, but returns control to the calling code, where execution continues from the next line (see screenshot).


    After the operation on the AWAIT line is completed, control will return to the _Connect method on the next line after the AWAIT statement. That is, the AWAIT operation is run as a background thread (although it is claimed that this is not always the case, and in some cases the compiler simply simulates asynchronous operation with jump commands).

    In your example, the Connect method (without the underscore) is essentially trying to read the IsConnected property immediately without waiting for the asynchronous task to complete. And the code continues executing by exiting the Connect method. This leads to unpredictable consequences.

    Best regards,
    Leonid
    Best regards,
    Leonid
    Attachments:

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 18:06 #25464

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Leonid,
    ok, so I'm again totally wrong.
    "await" means that the execution should NOT wait, but continue. Then it makes sense that the calling method must be flagged as "async".
    But then after this call I should be able to loop with sleep statements until the background task is finished, doing somethings like this:
    self:_ListDirectory( cPath )
    while _lSuccess == false
    	System.Diagnostics.Debug.WriteLine( "Waiting on ListDirectory" )
    	System.Threading.Thread.Sleep( 100 )
    end
    if _lSuccess
    	oReturn				:= _oEntryList
    endif
    But the strange thing is that the in the called method the code is never executed (I have traced that with Debug.WriteLine() calls):
    _lSuccess := false
    System.Diagnostics.Debug.WriteLine( "creating task" )
    oTask := _oClient:GetListing( cSearch, FtpListOption.AllFiles )
    System.Diagnostics.Debug.WriteLine( "awaiting task" )
    await oTask
    System.Diagnostics.Debug.WriteLine( "task finished" )
    _lSuccess := true

    The "task finished" message never arrives, and the _lSuccess is never set to true.

    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 18:12 #25465

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Leonid,
    theoretically (at least for a dummy like me) is should be relatively easy to do:
    I would only like to start something in the background and check periodically in the foreground if the background process is finished.
    But it seems that this is not possible.
    So I have to give up on that and search something other.
    Wolfgang
    P.S. strange enough, in a WPF environment that works
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 18:45 #25466

    • leon-ts
    • leon-ts's Avatar


  • Posts: 280
  • Hi Wolfgang,
    If this is a GUI application, then upon completion of the asynchronous task (next line, after the AWAIT statement), you can try send a notification message to the window; having received it in the Dispatch method, you will know that the operation has completed and do something about it.
    _oClient := AsyncFtpClient{ cHostName, cUserName, cPassword }
    oTask := _oClient:Connect()
    await oTask
    PostMessage(SomeWndHandle, WM_USER + ..., IIF(_oClient:IsConnected, 1, 0), 0)

    The line after AWAIT is executed on the main thread, so interacting with the GUI is safe.

    P.S. I didn't do such interactions (notifying the window when an asynchronous operation has completed). I prefer to work with classic threads.

    Best regards,
    Leonid
    Best regards,
    Leonid

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 18:53 #25467

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Leonid,
    unfortunately this is not a GUI application - I need that for a COM library.
    The FTPS library I use has two families of methods: synchronous and asynchronous.
    Until now, I have only used the synchronous methods, and they work well. But for longer transfers I need a sort of progress comunication, and I have failed to implement that with COM callbacks.
    Then I have tried to use the asynchronous methods - normally much better suited for network operations.
    I will try your suggestion, but it seems that at least the GetListing() call stops in the await and never goes forward, even if I make the main thread sleep.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    Async question 01 Mar 2023 21:42 #25473

    • NickFriend
    • NickFriend's Avatar


  • Posts: 246
  • Hi Wolfgang,

    I'm not entirely sure what exactly you need to achieve, but if the idea is to call _oClient:Connect(), then call _ListDirectory when the Connect call has completed, all you need to do is to place the _ListDirectory() call on the line after your await statement.

    As Leonid pointed out, the "awaited" method will be started and run in the background. In the meantime application control returns to the calling method. Then as soon as the awaited method completes it will resume execution with the code following the await call.

    Our app uses async/await very extensively and once you get the pattern clear in your head it works absolutely seamlessly and the code is much clearer than the older style BackgroundWorker.

    Nick

    Please Log in or Create an account to join the conversation.

    Last edit: by NickFriend.

    Async question 02 Mar 2023 05:58 #25476

    • wriedmann
    • wriedmann's Avatar
    • Topic Author


  • Posts: 3367
  • Hi Nick,
    what can I do in the main thread to wait until the background/async thread finishes?
    Thank you very much!
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.