Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.64/11: Рейтинг темы: голосов - 11, средняя оценка - 4.64
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
1

Ожидание task - в чем ошибка

07.04.2015, 18:50. Показов 1935. Ответов 21
Метки нет (Все метки)

Добрый день!

Такой код отрабатывает моментально. Хотя по логике на каждый элемент массива должно тратиться 1000 мс. То есть не работает ожидание выполнения всех тасков. В чем ошибка?



C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 private void button2_Click(object sender, EventArgs e)
        {
         DateTime dt = DateTime.Now;
 
            Task[] tasks = new Task[10];
            for (int i = 0; i < 10; i++)
                tasks[i] = Task.Factory.StartNew(() => Process(i));
 
 
            Task.WaitAll(tasks);
 
            textBox2.Text = (DateTime.Now - dt).TotalSeconds.ToString();
 
 
        }
 
        static void Process(int i)
        {
            Thread.Sleep(1000);
        }
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.04.2015, 18:50
Ответы с готовыми решениями:

Task и ожидание
Добрый день. Подскажите пожалуйста, как дождаться завершения выполнения всех фоновых задач? ...

Запуск нескольких Task-ов и ожидание их выполнения
Всем доброго времени суток. Мне необходимо отправлять сразу несколько запросов на линки какого-либо...

Ожидание завершения Task
Аналогичная проблема как тут https://www.cyberforum.ru/csharp-beginners/thread1287711.html...

Ожидание завершения Task
Здравствуйте, возникла проблемка, гугл не помог. Есть похожие проблемы, но их решение мне не...

21
Эксперт .NET
14953 / 11329 / 2970
Регистрация: 17.09.2011
Сообщений: 18,979
07.04.2015, 19:04 2
Здравствуйте!

Цитата Сообщение от Suppir Посмотреть сообщение
Такой код отрабатывает моментально.
Моментально — это в текстбоксе 0 секунд показывает?

Если в районе 1-3 секунд, то все нормально.
0
Master of Orion
Эксперт .NET
6082 / 4938 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
07.04.2015, 19:06 3
Suppir, ну так потому что задачи одновременно стартуют

Добавлено через 2 минуты
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
 
namespace ConsoleApplication8
{
    class Program
    {
        static void Main(string[] args)
        {
            var timeout = TimeSpan.FromSeconds(0.5);
 
            var sw = Stopwatch.StartNew();
            Task[] tasks = new Task[10];
            tasks[0] = new Task(() => Thread.Sleep(timeout));
            for (int i = 1; i < tasks.Length; i++)
            {
                tasks[i] = tasks[i - 1].ContinueWith(_ => Thread.Sleep(timeout));
            }
            tasks[0].Start();
 
            Task.WaitAll(tasks);
            sw.Stop();
 
            Console.WriteLine("Expected timeout = {0}, actual timeout = {1}", timeout.TotalMilliseconds*tasks.Length, sw.Elapsed.TotalMilliseconds);
        }
    }    
}
0
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
07.04.2015, 19:07  [ТС] 4
kolorotur, нет, ждет 2 - 3 секунды, а потом показывает 2 миллисекунды.
А должен показывать как минимум 1000 миллисекунд - ведь это минимальное время исполнения кода.
0
Master of Orion
Эксперт .NET
6082 / 4938 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
07.04.2015, 19:07 5
Suppir, ну это что-то странное...
0
Suppir
07.04.2015, 19:08  [ТС]
  #6

Не по теме:

Psilon, решил, наконец-то, изучить .NET Framework 4.0.
Буду переделывать одну программу под этот фреймворк.

0
Эксперт .NET
14953 / 11329 / 2970
Регистрация: 17.09.2011
Сообщений: 18,979
07.04.2015, 19:09 7
Цитата Сообщение от Suppir Посмотреть сообщение
потом показывает 2 миллисекунды.
То есть значение в текстбоксе выглядит примерно так: 0.002?
0
Warrior
497 / 424 / 177
Регистрация: 23.11.2014
Сообщений: 932
07.04.2015, 19:11 8
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
 
class Class1
{
    static void Main()
    {
        MainAsync().Wait();
    }
 
    static async Task MainAsync()
    {
        Stopwatch sw = new Stopwatch();
 
        Task[] tasks = new Task[10];
        sw.Start();
        for (int i = 0; i < 10; i++)
            tasks[i] =  Task.Factory.StartNew(() => Process(i));
        
 
        Task.WaitAll(tasks);
        sw.Stop();
 
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
    static void Process(int i)
    {
        Thread.Sleep(1000);
    }
}
мне выдало 2062 в консоли
0
Миниатюры
Ожидание task - в чем ошибка  
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
07.04.2015, 19:13  [ТС] 9
Цитата Сообщение от Psilon Посмотреть сообщение
Suppir, ну это что-то странное...
А! Пардон, я перепутал!

C#
1
textBox2.Text = (DateTime.Now - dt1).TotalSeconds.ToString();
То есть показывает все правильно - 2 секунды. Я думал, что поставил подсчет в миллисекундах.

Подождите, пока не удаляйте тему, я хочу изучить код Psilon.

Добавлено через 1 минуту
Цитата Сообщение от kolorotur Посмотреть сообщение
То есть значение в текстбоксе выглядит примерно так: 0.002?
Нет, там показывает 2. Я что-то заработался, подумал, что это 2 миллисекунды.
0
Эксперт .NET
14953 / 11329 / 2970
Регистрация: 17.09.2011
Сообщений: 18,979
07.04.2015, 19:17 10
Цитата Сообщение от Suppir Посмотреть сообщение
подумал, что это 2 миллисекунды.
Отсюда и вопросы про вывод

Цитата Сообщение от Suppir Посмотреть сообщение
пока не удаляйте тему
Не припомню, чтобы здесь удаляли темы, хотя бы даже отдаленно связанные с тематикой раздела.
0
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
07.04.2015, 19:42  [ТС] 11
Еще такой вопрос возник. Имеем следующий код:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
            DateTime dt = DateTime.Now;
 
            Task task = Task.Factory.StartNew(() =>
            {
                Parallel.ForEach(Files, file =>
                {
                    textBox1.Invoke((Action)delegate { textBox1.AppendText(file + "\n"); });
                    ParseFile(file);
                });
            });
 
            task.Wait();
 
            textBox2.Text = (DateTime.Now - dt).TotalSeconds.ToString();
Parallel.ForEach обернут в task, поэтому должен выполняться в отдельном от UI потоке. Но при этом программа зависает!

Если же убрать строчку:
C#
1
textBox1.Invoke((Action)delegate { textBox1.AppendText(file + "\n"); });
тогда программа работает.

Можете объяснить, в чем ошибка?

Добавлено через 8 минут
Если
C#
1
textBox1.Invoke
заменить на
C#
1
 textBox1.BeginInvoke
, то программа работает, НО:
все файлы выводятся за один раз уже после завершения обработки. А мне нужно, чтобы выводились по мере запуска обработки.
0
2291 / 1739 / 521
Регистрация: 02.08.2011
Сообщений: 4,950
07.04.2015, 20:01 12
Цитата Сообщение от Suppir Посмотреть сообщение
Можете объяснить, в чем ошибка?
а Files - это массив путей к файлам?
0
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
07.04.2015, 20:10  [ТС] 13
Цитата Сообщение от IamRain Посмотреть сообщение
а Files - это массив путей к файлам?
Да, массив путей к файлам. А метод ParseFile читает и обрабатывает файлы. Мне нужно через Parallel.ForEach читать файлы и выводить в textbox названия этих файлов. А по окончанию работы - показать время исполнения кода.
0
2291 / 1739 / 521
Регистрация: 02.08.2011
Сообщений: 4,950
07.04.2015, 20:45 14
Мое предположение:
Метод Control.Invoke - синхронный метод, то есть получается, что он возращает управление уже после того, как завершится операция в потоке Control-а. Но поскольку вы со своим любимым TPL решили использовать Parallel.ForEach, то в цикл обработки сообщений окна вашего control-а падает целая пачка задач, которые он начинает честно выполнять. Видимо, зависает из за того, что из-за большого кол-ва задач все остальными события формы просто висят где-то в очереди задач. Тут копать в Windows Internals надо, чтобы толком все объяснить.
Цитата Сообщение от Suppir Посмотреть сообщение
все файлы выводятся за один раз уже после завершения обработки.
Тут, видимо, что-то с приоритезацией потоков. Если используете BeginInvoke, тогда вызывайте ваш ParseFile метод в EndInvoke, который, по определению, вызывается автоматически после завершения асинхронной операции. Это первый способ попробовать исправить ошибку.
Второй способ: использовать вместо Parallel обычный foreach, ведь вам же нужно заполнять textbox синхронно. Как-то так.

Не по теме:

Suppir, Task-и - это конечно крутая фича, но в программировании всегда нужно понимать, что ты пишешь. :)

0
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
07.04.2015, 21:05  [ТС] 15
Хорошо. А как мне апдейтить textbox в то время, когда выполняется Parallel.Foreach()?
То есть мне нужно, чтобы в textbox выводились файлы, который сейчас обрабатываются (или которые уже обработались). Как это сделать без подвисания программы?

Добавлено через 11 минут
Кажется, понял. В данном случае вместо Task.Wait использовать Task.ContinueWith()
0
Master of Orion
Эксперт .NET
6082 / 4938 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
07.04.2015, 21:25 16
Suppir, ну по сути параллельно вы ничего не делаете, потому что все равно делаете Invoke. То есть Parallel и таски тут абсолютно ничего не делают, кроме отжирания ресурсов на создание объектов. Вообще ничего. Всё как выполнялось в главном потоке с подвисанием формы, так и выполняется.
0
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
07.04.2015, 21:38  [ТС] 17
Psilon, а что же тогда делать?

Мне нужно, чтобы в textbox выводились файлы, который сейчас обрабатываются (или которые уже обработались). А по завершении задачи нужно вывести время исполнения в textbox.
0
Master of Orion
Эксперт .NET
6082 / 4938 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
07.04.2015, 22:25 18
Suppir, ну так только код вывода в текстбокс (и только его!) в Invoke
0
25 / 25 / 10
Регистрация: 08.08.2011
Сообщений: 1,160
07.04.2015, 22:27  [ТС] 19
Исправил на вот такой код (работает):

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
    DateTime dt = DateTime.Now;
 
            Task task = Task.Factory.StartNew(() =>
            {
                Parallel.ForEach(Files, file =>
                {
                    textBox1.Invoke((Action)delegate { textBox1.AppendText(file + "\n"); });
                    ParseFile(file);
                });
            //после завершения обработки файлов
            }).ContinueWith((result)=>{
                textBox2.Invoke((Action)delegate { textBox2.Text = (DateTime.Now - dt).TotalSeconds.ToString(); });
            });
Добавлено через 52 секунды
Но вот это "ContinueWith" - не нравится совсем. Особенно, если нужно несколько операций сделать друг за другом. Хочу еще попробовать await async.
0
Эксперт .NETАвтор FAQ
9960 / 4836 / 1745
Регистрация: 11.01.2015
Сообщений: 6,019
Записей в блоге: 34
07.04.2015, 22:30 20
Цитата Сообщение от Suppir Посмотреть сообщение
Мне нужно, чтобы в textbox выводились файлы, который сейчас обрабатываются (или которые уже обработались). А по завершении задачи нужно вывести время исполнения в textbox.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Linq;
 
namespace WindowsFormsApplication269
{
    public partial class Form1 : Form
    {
        private RichTextBox tb;
 
        public Form1()
        {
            InitializeComponent();
 
            var bt = new Button {Parent = this, Text = "Start!"};
            bt.Click += new EventHandler(bt_Click);
 
            tb = new RichTextBox {Parent = this, Dock = DockStyle.Fill, ReadOnly = true};
        }
 
        void bt_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(Work);
        }
 
        void Work()
        {
            var sw = Stopwatch.StartNew();
 
            var files = Enumerable.Range(1, 100);
            Parallel.ForEach(files, ProcessFile);
 
            sw.Stop();
            AppendTextToTb(sw.Elapsed.ToString());
        }
 
        private void AppendTextToTb(string str)
        {
            if(InvokeRequired)
            {
                Invoke((Action)(()=>AppendTextToTb(str)));
                return;
            }
            tb.AppendText(str + "\r\n");
        }
 
        private void ProcessFile(int file)
        {
            AppendTextToTb("Processing " + file + "...");
            Thread.Sleep(1000);
        }
    }
}
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.04.2015, 22:30

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Чем черевато запуск множества Task
Заранее извиняюсь, ассинхронность это не совсем моё. Поэтому бить меня сильно не надо) У меня есть...

В чем разница между Task и Thread?
В чем разница между Task и Thread и когда что лучше использовать? Если для написания сервера...

В чем разница между Dispatcher и Task, где что лучше использовать?
Форумчане, расскажите в чем разница между Dispatcher и Task, где что лучше использовать? Есть два...

[UWP] Возвращаемым типом асинхронного метода должен быть void, Task или Task<T>
Создал асинхронный метод. Он должен на выходе вывести объект который состоит из строк. Пишет...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.