Как сделать задачу после другой задачи в vb.net?

    For Each account In _accounts11
        Dim newtask = account.readbalancesAsync()
        newtask = newtask.ContinueWith(Sub() account.LogFinishTask("Getting Balances", starttime))
        newtask = newtask.ContinueWith(Async Function() account.getOrdersAsync())
        newtask = newtask.ContinueWith(Sub() account.LogFinishTask("Getting Orders", starttime))

        tasklist.Add(newtask)
    Next


    Await Task.WhenAll(tasklist.ToArray)
    Dim b = 1

По сути, для каждой учетной записи я хочу сделать account.readbalancesAsync, а после этого я хочу сделать account.getOrdersAsync().

Я оставил код newtask.ContinueWith(Sub() account.LogFinishTask("Getting Balances", starttime)), чтобы показать, что знаю, как работает ContinueWith. Однако после этого мне нужно продолжить другую задачу.

Как мне это сделать?

То, что я пытаюсь сделать, это что-то вроде этого

    For Each account In _accounts11
        await account.readbalancesAsync()
        account.LogFinishTask("Getting Balances", starttime)
        await account.getOrdersAsync())
        account.LogFinishTask("Getting Orders", starttime)

        tasklist.Add(newtask)
    Next

Очевидно, что если я сделаю это так, то одной учетной записи придется ждать завершения работы другой учетной записи. Я хочу, чтобы все учетные записи работали параллельно.

Или давайте посмотрим на этот код

dim response1 = await client.GetAsync("http://example.com/");
dim response2 = await client.GetAsync("http://stackoverflow.com/");

Скажи, что я делаю это так

dim newtask = client.GetAsync("http://example.com/").continueWith(....)
await newtask

Что мне поставить....


person user4951    schedule 29.04.2019    source источник
comment
Вы уже запускаете задачи продолжения несколько раз. Что мешает вам продолжать звонить ContinueWith? Хотя мне очень хотелось бы знать, почему вы в первую очередь используете все эти задачи продолжения, а не просто заключаете все в лямбда-блок Sub()/End Sub? Поскольку каждая задача уже запущена в фоновом режиме, нет смысла создавать их больше, чем необходимо.   -  person Visual Vincent    schedule 29.04.2019
comment
По сути, для каждой учетной записи я хочу выполнить await account.readbalancesasync, а затем await account.getordersasync. Однако я хочу, чтобы они работали параллельно, а не последовательно.   -  person user4951    schedule 29.04.2019
comment
Я знаю, как использовать continueWith с неблокирующей нормальной функцией. Теперь я хочу использовать continueWith с асинхронной функцией.   -  person user4951    schedule 29.04.2019


Ответы (2)


Я думаю, вы по ошибке где-то свернули не туда. Если вам нужно запустить эти четыре оператора друг за другом, но без вмешательства в цикл, все, что вам нужно сделать, это создать одну задачу, выполняющую многострочное/блочное лямбда-выражение.

Например:

For Each account In _accounts11
    Dim newtask = Task.Run( 'Start a new task.
        Async Function() 'Multiline lambda expression.
            Await account.readbalancesAsync()
            account.LogFinishTask("Getting Balances", starttime)
            Await account.getOrdersAsync()
            account.LogFinishTask("Getting Orders", starttime)
        End Function
    ) 'End of Task.Run()

    tasklist.Add(newtask)
Next
person Visual Vincent    schedule 29.04.2019
comment
Это способ. Можете ли вы сделать это с continueWith вместо этого? - person user4951; 29.04.2019
comment
@ user4951: Могу я спросить, почему? ContinueWith не предназначен для использования таким образом, и запуск нескольких новых задач, подобных этому, повлияет на производительность (даже если это может быть незаметно, в этом нет необходимости). - person Visual Vincent; 29.04.2019
comment
Я думаю, это как-то странно. Я могу использовать continueWith с обычной функцией, но не могу использовать ее с ожидаемой функцией. Также выполняется ли task.run в том же потоке? - person user4951; 29.04.2019
comment
@ user4951 : Пожалуйста, объясните, почему вы не можете использовать ContinueWith с ожидаемой функцией. Чего вы ожидаете, и что происходит вместо этого? -- Кроме того, нет: Task.Run() запускает совершенно новую задачу, работающую в любом потоке (потоках), который ОС решит запустить (помните: задачи могут переключаться между разными потоками, но вы можете быть уверены, что они всегда будут выполняться в том или ином потоке). background - так что не в том же потоке). - person Visual Vincent; 29.04.2019
comment
обычная асинхронная ожидание запускается на переднем плане. Вы сказали, что я могу использовать ContinueWith с ожидаемой функцией. Как именно я должен это сделать? Спасибо. - person user4951; 29.04.2019
comment
@ user4951: Нет, это не так. Async/Await примерно работает, возвращая управление вызывающему потоку в ту секунду, когда вы нажимаете Await. Это позволяет вызывающему потоку продолжать работу до тех пор, пока не будет получен ответ и не завершится Await. Затем вызывающий поток получает указание продолжить выполнение кода, расположенного после Await. Если вы используете ContinueWith или отдельную задачу, она будет выполняться в одном или нескольких вторичных потоках. -- Отредактировал ответ, чтобы включить пример ContinueWith. - person Visual Vincent; 29.04.2019
comment
О, круто. Спасибо. Значит, мы используем асинхронную подпрограмму, а не асинхронную функцию? Уверен? - person user4951; 29.04.2019
comment
@ user4951: Как я уже сказал, я не тестировал код, но и Function, и Sub должны работать нормально. Хотя я предполагаю, что технически это должно быть Function, так как Await обычно возвращает Task. - person Visual Vincent; 29.04.2019
comment
@user4951 user4951: Для справки, если вы хотите запустить свой код параллельно, при этом имея возможность напрямую получить доступ к пользовательскому интерфейсу (основному потоку), то это невозможно. Само определение параллельной работы состоит в том, чтобы разделить работу между отдельными объектами. Для компьютера это потоки. Вы не можете запускать два процесса одновременно в одном потоке. Если вам нужно запустить что-то параллельно, вам нужна многопоточность, и если вам нужно получить доступ к пользовательскому интерфейсу из фонового потока, вам нужно вызвать. - person Visual Vincent; 29.04.2019
comment
Я понимаю. Я думаю, что весь мой код будет работать в основном потоке. Что-то еще может работать в другом потоке. Вот чем асинхронное ожидание отличается от других многопоточных подходов. - person user4951; 29.04.2019
comment
Определенно есть какое-то предупреждение компилятора, говорящее: «Почему бы вам не попробовать это самостоятельно, прежде чем я выберу ваш ответ». я уже проголосовал за тебя - person user4951; 29.04.2019
comment
@ user4951: Async/Await не о многопоточности. Это буквально просто о том, чтобы делать что-то еще, пока вы ждете завершения вашего первого процесса. Будь то получение чего-либо из базы данных/сервера или выполнение вычислений, это не имеет значения. Это имеет мало или вообще ничего общего с многопоточностью. Задачи, с другой стороны, делают это. - person Visual Vincent; 30.04.2019
comment
@ user4951: К сожалению, я сижу на своем телефоне, поэтому не могу его протестировать (переключитесь на Functions, если он жалуется), и я также не совсем уверен, какова ваша цель и как вы хотите, чтобы это работало. Однако, похоже, у вас нет веской причины использовать ContinueWith. Это только кажется расточительным. - person Visual Vincent; 30.04.2019
comment
@ user4951: Я попробовал пример ContinueWith на dotnetfiddle и решил отказаться от него, потому что не смог заставить его работать. Это просто не то, как должны использоваться методы Async, и у вас нет веских причин делать это таким образом. Как я уже сказал, невозможно выполнять работу параллельно только в одном потоке. Даже ContinueWith создает новую задачу, работающую в (а) отдельном потоке (потоках). Если вам нужно получить доступ к элементам управления или компонентам в пользовательском интерфейсе (основном потоке) из этих параллельных процессов, единственный вариант — сделать это с помощью вызова< /а>. - person Visual Vincent; 30.04.2019

Я просто хочу добавить кое-что к ответу VisualVincent. Я все еще предпочитаю делать это с continueWith

Private Async Function readBalancesAndOrderForEachAccount(starttime As Long) As Task
    Await readbalancesAsync()
    LogFinishTask("Getting Balances", starttime)
    Await getOrdersAsync()
    LogFinishTask("Getting Orders", starttime)
End Function

Public Shared Async Function getMarketDetailFromAllExchangesAsync2() As Task
    Dim CurrentMethod = MethodBase.GetCurrentMethod().Name
    Dim tasklist = New List(Of Task)
    Dim starttime = jsonHelper.currentTimeStamp

...

        For Each account In _accounts11
            Dim newtask = account.readBalancesAndOrderForEachAccount(starttime)
            tasklist.Add(newtask)
        Next
        Await Task.WhenAll(tasklist.ToArray)
        Dim b = 1
   ...
    End Function

Кажется, это работает. Однако я хочу понять, как это сделать с помощью continueWith, потому что мне очень любопытно.

person user4951    schedule 29.04.2019
comment
Если вы переместите вызов LogFinishTask внутрь соответствующих методов, вы можете просто получить: Dim newtask As Task = readbalancesAsync().ContinueWith(Async Function(t) Return Await getOrdersAsync() End Function). getOrdersAsync() может вернуть Task(Of Boolean): вы просто возвращаете True или False. Обратите внимание, что в VB.Net лямбда Function(t) должна быть записана в 3 строки. - person Jimi; 29.04.2019
comment
Вы не должны использовать ContinueWith; это низкоуровневый, опасный метод. Await намного лучше во всех отношениях. - person Stephen Cleary; 30.04.2019
comment
ContinueWith отлично работает для меня. Я просто не могу сделать это с ожидаемыми функциями - person user4951; 30.04.2019