S
S
skvoshiz2014-11-21 03:32:19
Programming
skvoshiz, 2014-11-21 03:32:19

How to start a Task after it's done?

Hello, I ran into a problem that I still can’t solve:
There is a button, when pressed, a method is called:

private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            OnlyLike();           
        }

In the method, the Task thread is called, upon completion of which the response is added to the TextBox.Text
public void OnlyLike()
        {
            Task<string> LikeTurbo = VK.NakrytkaLike(KeyAntigateTextBox.Text);
            LikeTurbo.ContinueWith(task =>
            {
                TextBox.Text += LikeTurbo.Result.ToString();
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }

The question is how to make it so that when the button is pressed, the OnlyLike Method is executed several times (for example, 5), BUT so that this method starts again only after the Task LikeTurbo thread is completed

Answer the question

In order to leave comments, you need to log in

3 answer(s)
M
mayorovp, 2014-12-02
@skvoshiz

I did not understand a little, do you need to run tasks sequentially or in parallel? And if in parallel - then process the results at once or together?
1. Sequential start:

private async void OnlyLike()
{
    for (var i=0; i<5; i++)
        TextBox.Text += await VK.NakrytkaLike(KeyAntigateTextBox.Text);
}

2. Parallel launch, processing all results together
private async void OnlyLike()
{
    var tasks = Enumerable.Range(0, 5).Select(i => VK.NakrytkaLike(KeyAntigateTextBox.Text));
    foreach (var result in await Task.WhenAll(tasks))
        TextBox.Text += result;
}

3. Parallel run, processing results immediately:
private async void OnlyLike()
{
    TextBox.Text += await VK.NakrytkaLike(KeyAntigateTextBox.Text);
}

private void StartButton_Click(object sender, RoutedEventArgs e)
{
    for (var i=0; i<5; i++)
        OnlyLike();
}

Choose what you like. And don't be afraid to use async/await - it's designed to simplify the code, not to complicate it :)
UPD Running
sequentially on framework 4.0:
public void OnlyLike()
{
    var scheduler = TaskScheduler.Current ?? TaskScheduler.FromCurrentSynchronizationContext();
    Task task = TaskEx.FromResult(false);
    var text = KeyAntigateTextBox.Text;
    for (var i=0; i<5; i++) {
        task = task.ContinueWith(_ => {
            var LikeTurbo = VK.NakrytkaLike(text);
            LikeTurbo.ContinueWith(_ => {
                 TextBox.Text += LikeTurbo.Result;
            }, scheduler);
            return LikeTurbo;
        }, TaskContinuationOptions.ExecuteSynchronously).Unwrap();
    }
}

...

public static class TaskEx {
    public static Task<T> FromResult<T> (T result) {
        var tcs = new TaskCompletionSource<T>();
        tcs.SetResult(result);
        return tcs.Task;
    }

    public static Task<T> Unwrap<T>(this Task<Task<T>> task) {
        var tcs = new TaskCompletionSource<T>();
        task.ContinueWith(_ => {
            if (task.IsCanceled) tcs.SetCancelled();
            else if (task.IsFaulted) tcs.SetException(task.Exception);
            else task.Result.ContinueWith(innerTask => {
                if (innerTask.IsCanceled) tcs.SetCancelled();
                else if (innerTask.IsFaulted) tcs.SetException(task.Exception);
                else tcs.SetResult(innerTask.Result);
            }, TaskContinuationOptions.ExecuteSynchronously);
        }, TaskContinuationOptions.ExecuteSynchronously);
        return tcs.Task;
    }
}

It looks verbose, but in fact - nothing complicated. In the loop, tasks are queued one after the other using the task = task.ContinueWith(...).Unwrap() construct. Here Unwrap() is a function that allows you to wait for the execution of a child task, in fact, a simple unwrapper of the Task Task T -> Task T monad.
Inside such a loop is, in fact, the old code of the OnlyLike() method - with the exception that now it also returns the task that it created (this is necessary to wait for it to complete). Here I allowed myself a slight acceleration - since I wrote return LikeTurbo - each next iteration of the loop will only wait for the previous task VK.NakrytkaLike - but will not wait for the previous results to be displayed on the screen. If it is important to wait for the output of the results, then it is necessary to return not LikeTurbo, but the result of ContinueWith.
Also, the location of the call to TaskScheduler.FromCurrentSynchronizationContext(); is very important here. Since at the moment of execution of the last task we can be in any context, it is impossible to focus on the current context. The task scheduler we need should be saved when entering the method (for the future: it should be _always_ saved _only_ when entering the method!)

V
Vitaly Pukhov, 2014-11-21
@Neuroware

The problem here is rather architectural, if something like this is required, then something is wrong here, but in general, nothing prevents wrapping it all in a separate Task or Thread and sequentially calling tasks in it as many times as you want.

1
1hroft1, 2014-11-21
@1hroft1

for(var i=1; i<=5; i++)
{
    Console.WriteLine("Сейчас будем запускать продолжающиеся потоки в " + i + " раз");
    Task<string> LikeTurbo = Task.Factory.StartNew<string>(()=>
    {
        Console.WriteLine("Выполнение в первом потоке №"+i);
        return "somestring";
    });
    Task cont_task=LikeTurbo.ContinueWith(task =>
    {
        Console.WriteLine("Выполнение во втором потоке №" + i);
    });
     cont_task.Wait();
}

UPD. And here are some useful tasks for you dotnetcodr.com/task-parallel-library

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question