Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Проблема с потоками


Автор: ДобренькийПапаша 28.4.2010, 12:09
Решил всё-таки отдельную тему сделать, попробую сформулировать правильно.

Из функции по делегату в новом потоке вызывается функция парсинга текстового файла (выдираются значения для графика).
Код

  private void StartParsing(ParseCall parseFunc)
        {
            ParseCall parseCall = parseFunc;
            Thread chart = new Thread(parseCall.Invoke);
            chart.Start();
            
            //chart.Join();
            //for (int i = 0; i < this.x.Count; i++)
            //{
            //   currentChart.Series[0].Points.AddXY(x, this.high[i], this.low[i], this.open[i], this.close[i]);
            //}  
        }


Сам метод парсинга:
Код

private void ParseFileToStockChart()
        {
               //Тут куча работы по парсингу (которую я опустил) и, далее, собственно, прикручивание точек к графику
                if (currentChart.InvokeRequired)
                {
                    Invoke(new Action(() => currentChart.Series[0].Points.AddXY(DateTime.Parse(date), high, low, open, close)));
                } 
        }


Из-за того, что прикручивание находится в блоке InvokeRequired, то прикручивание происходит очень медленно, т.е. я некоторое время наблюдаю как точка за точкой появляются на графике...
Соответственно надо это вынести в основной поток, откуда был запуск, но если в функции StartParsing раскомментить строки, то почему-то, дальше chart.Join() выполнение не идёт (ждал долго, быть такого не может).

Короче, какой может быть выход из сложившейся ситуации?

Автор: Miller_time 28.4.2010, 12:20
А у тебя 

Код

currentChart


находиться в разных потоках? Может быть просто дожидаеться пока, один поток закончит, работы с обьектом и передаст управление другому обьекту. 

Автор: ДобренькийПапаша 28.4.2010, 12:39
Цитата(Miller_time @ 28.4.2010,  12:20)
А у тебя 

Код

currentChart


находиться в разных потоках? Может быть просто дожидаеться пока, один поток закончит, работы с обьектом и передаст управление другому обьекту.

В разных потоках находится.  По поводу дождаться читайте выше.

Автор: Heinzz 28.4.2010, 13:27
а ежели Invoke не Required smile 

Автор: ДобренькийПапаша 28.4.2010, 13:59
Цитата(Heinzz @ 28.4.2010,  13:27)
а ежели Invoke не Required smile

Это вы к чему?

p.s. Пожалуйста, не пишите в тему, если не знаете как решить проблему.

Автор: mrbrooks 28.4.2010, 14:46
ДобренькийПапаша, не совсем понятно - заполнение графика идет во время парсинга или уже с формированным набором данных?
Если первое - то имхо - это не очень удачное решение.
Если второе - передай массив данных как параметр в функцию, адрес которой передаешь потоку.
Код

public void Run()
{
 //формируешь List<TROLOLO>data , где TROLOLO - есть сущность характеризующая данные взятые из файла. 
 Thread th = new Thread(WorkFunc);
 th.Start(data);
}

private void WorkFunc(object obj)
{
        List<TROLOLO>data = (List<TROLOLO>)obj;
        for(int i = 0; i<TROLOLO.Count;i++)
        {
                if (InvokeRequired)
                {
                    Invoke(new Action(() => currentChart.Series[0].Points.AddXY(DateTime.Parse(date), TROLOLO[i].high,...)));
                } 
                 else
                 {
                    currentChart.Series[0].Points.AddXY(DateTime.Parse(date), TROLOLO[i].high,...);
                 }
        }
}



зы. и в догонку что используете - MS Chart? Это реально важно - ибо здесь уже можно задействовать гораздо более эффективные способы вывода данных.

Автор: ДобренькийПапаша 28.4.2010, 19:17
Использую MSChart. Сейчас график наполняется точками в функции парсинга, это как вы сказали неудачно. Так и есть! Я же написал, что я в функции парсинга, запущенной в новом потоке мне приходится обращаться через InvokeReqiured к графику... что замедляет очень сильно наполнение графика точками. Я пытался сделать так, чтобы результаты парсинга присваивались коллекциям на уровне класса, чтобы прикрутить точки к графику уже в основном потоке, но какие я встретил проблемы я тоже описал выше...

Автор: mrbrooks 28.4.2010, 23:01
Ок. Я понимаю вашу озабоченность. Если вы используете M$ Chart - то используйте всю его мощь при работе с наборами данных. Продемонстрирую на примере:
Есть класс - характеризующий некую сущность - в моем случае координаты по Х и У:
Код

    public class ClassPoints
    {
        private int _x;
        private int _y;

        public int x
        {
            get { return _x; }
            set { _x = value; }
        }

        public int y
        {
            get { return _y; }
            set { _y = value; }
        }

        public ClassPoints(int x, int y)
        {
            this._x = x;
            this._y = y;
        }
    }


Тогда общее решение:
Код

        Random rand = new Random();
        BindingList<ClassPoints> list = new BindingList<ClassPoints>();

        private void Run()
        {
            for (int i = 0; i < 10000; i++) list.Add(new ClassPoints(i, rand.Next(1, 50))); //10000!!!!
            new Thread(WorkFunc).Start();
        }

        private void WorkFunc()
        {
            //Stopwatch sw = Stopwatch.StartNew();
            if (this.InvokeRequired) this.Invoke(new Action(() => BindingList2Chart()));
            else BindingList2Chart();
            //MessageBox.Show(sw.Elapsed.ToString());
        }

        private void BindingList2Chart()
        {
            chart1.DataSource = list;
            chart1.Series[0].XValueMember = "x";
            chart1.Series[0].YValueMembers = "y";
            chart1.DataBind();
        }


Данный код вывел 10000 точек менее чем за секунду (у меня есесно).

У меня складывается впечатлении что мы с вами уже этот вопрос обсуждали. Речь шла о парсинге CSV файла. Если это та же история я настоятельно рекомендую использовать все стандартные возможности для работы с файлом как с БД. Это быстрее и надежнее, чем строить по точкам и писать парсеры.

Автор: ДобренькийПапаша 29.4.2010, 07:55
Код

stockPoints.Add(new StockPoints(DateTime.Parse(date), high, low, open, close));
                
            if (currentChart.InvokeRequired)
            {
                Invoke(new Action(() =>
                {

                    currentChart.DataSource = stockPoints;
                    currentChart.DataBind();
                }));
            }
            else
            {
                currentChart.DataSource = stockPoints;
                currentChart.DataBind();
            }

Код

public class StockPoints
        {
            public DateTime X { get; private set; }
            public double High { get; private set; }
            public double Low { get; private set; }
            public double Open { get; private set; }
            public double Close { get; private set; }

            public StockPoints(DateTime x, double y1, double y2, double y3, double y4)
            {
                X = x;
                High = y1;
                Low = y2;
                Open = y3;
                Close = y4;
            }
        }
        BindingList<StockPoints> stockPoints = new BindingList<StockPoints>();

После завершения работы функции график остаётся белым. Посмотрел в отладчике, stockPoints имеет 80 точек как и должно быть, а вот после прохода функции currentChart.DataBind() currentChart.Series[0].Points.Count=0, т.е. привязка не произошла как я понимаю...

Автор: ДобренькийПапаша 29.4.2010, 08:24
Код

if (currentChart.InvokeRequired)
            {
                Invoke(new Action(() => currentChart.Series[0].Points.DataBindXY(this.x, this.high, this.low, this.open, this.close)));
            }
            else
            {
                currentChart.Series[0].Points.DataBindXY(this.x, this.high, this.low, this.open, this.close);
                //currentChart.DataSource = stockPoints;
                //currentChart.DataBind();
            }


Так всё работает и очень быстро, спасибо mrbrooks за подсказу использовать binding.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)