Почему моя программа C # Winforms с таймером зависает через день? - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть программа, которая обновляет два объекта DataGridView каждую минуту с помощью запроса MySQL из нашей внутренней базы данных заказов, чтобы мы могли отслеживать более старые заказы и следить за их обработкой.

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

Вот код таймера и функция, которую он вызывает:

    private void timer1_Tick(object sender, EventArgs e)
    {
        UpdateOrderDisplay();
    }

        private void UpdateOrderDisplay()
    {
        grdOrderItems.Rows.Clear();
        grdHoldOrders.Rows.Clear();
        string strsql;
        string CustomerName;
        string MyConString = "SERVER=**********;" + "DATABASE=***********;" + "UID=************;" + "PASSWORD=***********;";
        using (MySqlConnection connection = new MySqlConnection(MyConString))
        {
            MySqlCommand command = connection.CreateCommand();
            MySqlDataReader Reader;
            strsql = "select * from orders where ship_reference=0 and OnHold =0 order by order_id asc";
            command.CommandText = strsql;
            connection.Open(); Reader = command.ExecuteReader();
            while (Reader.Read())
            {
                if (Reader["payment_date"].ToString() != "")
                {
                    if (Reader["custom"].ToString().Contains("~*"))
                    {
                        CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
                    }
                    else
                    {
                        CustomerName = Reader["shipping_address_name"].ToString();
                    }
                    grdOrderItems.Invoke(new MethodInvoker(() => grdOrderItems.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString())));
                }
            }
            connection.Close();
            strsql = "select * from orders where OnHold =1 order by order_id asc";
            command.CommandText = strsql;
            connection.Open(); Reader = command.ExecuteReader();
            while (Reader.Read())
            {
                if (Reader["payment_date"].ToString() != "")
                {
                    if (Reader["custom"].ToString().Contains("~*"))
                    {
                        CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
                    }
                    else
                    {
                        CustomerName = Reader["shipping_address_name"].ToString();
                    }
                    grdHoldOrders.Invoke(new MethodInvoker(() => grdHoldOrders.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString(),Reader["Hold_Review_Date"].ToString().Substring(0,Reader["Hold_Review_Date"].ToString().IndexOf(" ")),Reader["payer_email"].ToString())));
                }
            }





            connection.Close();
        }

    }

Кроме того, в случае, если это уместно, вот код, который я использую, чтобы закрасить строки объекта DataGridView, чтобы мы могли легко определить, какой порядок более старый:

    private void grdOrderItems_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
    {
        grdOrderItems.RowPrePaint += new System.Windows.Forms.DataGridViewRowPrePaintEventHandler(this.grdOrderItems1_RowPrePaint);

    }
    private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
    {
        if (e.RowIndex <= grdOrderItems.Rows.Count - 1)
        {
            string StringNow = DateTime.Now.ToString();
            string NowTime = StringNow.Substring(StringNow.IndexOf(" ")+1, StringNow.Length- StringNow.IndexOf(" ")-1);
            string OrderDateTime = grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().IndexOf(" ")+1) + NowTime;
            if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 2)
            {
                grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tomato;
            }
            else
            {
                if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 1)
                {
                    grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Yellow;
                }
                else
                {
                    if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 0)
                    {
                        grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tan;
                    }

                }
            }
        }
    }

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

У меня недостаточно информации для полного ответа, кроме как сказать, что это пахнет проблемой кучи больших объектов, когда одно из полей, которые вы извлекаете из базы данных, иногда будет длиннее порога 85K LOH.

Что я могу сделать, и это может даже помочь, это показать вам, как значительно упростить и улучшить метод предварительной окраски, например:

private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
    if (e.RowIndex > grdOrderItems.Rows.Count - 1) return;
    var row = grdOrderItems.Rows[e.RowIndex];

    TimeSpan timeOfDay = DateTime.Now - DateTime.Today;
    //It *looks like* Cells[0].Value is already a DateTime, but I'm not 100% on this
    // If I'm wrong and it's a string, its worth it to parse just that one value to a DateTime here, and still plug that DateTime value into this code instead of the Cell.
    DateTime OrderDateTime = ((DateTime)row.Cells[0].Value).Date + timeOfDay;

    var days = (DateTime.Now - OrderDateTime).TotalDays;
    if (days > 2)
    {
        row.DefaultCellStyle.BackColor = Color.Tomato;
    }
    else if (days > 1)
    {
        row.DefaultCellStyle.BackColor = Color.Yellow;
    }
    else if (days > 0)
    {
        row.DefaultCellStyle.BackColor = Color.Tan;
    }
}

Это уменьшает вложенность и дополнительные блоки, делая его намного проще для понимания, и, вероятно, выполняется менее чем вдвое из-за уменьшенного возврата между значениями string и DateTime. Культурные проблемы / проблемы интернационализации делают преобразование между DateTime и строкой в ​​любом направлении по своей сути медленной и подверженной ошибкам операцией.

0 голосов
/ 13 ноября 2018

Возможно, у вас утечка MySqlDataReader.Когда вы закончите с каждым Reader объектом, избавьтесь от него.Это хороший способ сделать это;он устойчив к исключениям, и переменная reader выходит из области видимости в конце использования.

    using (var reader = command.ExecuteReader()
    {
        while (reader.Read())
        {
           /* your per-row logic here */
        }
    }

Вы также можете сделать это с помощью Close ():

    MySqlDataReader Reader; 
      ...
    Reader = command.ExecuteReader()
    while (Reader.Read())
    {
       /* your per-row logic here */
    }
    Reader.Close();

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

Вы можете оставить свое соединение открытым дольше, чем один таймер.(Если у вас есть пул подключений, игнорируйте этот совет.)

Используйте диспетчер задач, чтобы увидеть, сколько ЦП% и памяти занимает ваша программа (утром и снова вечером).Если память растет, у вас какая-то утечка.Если ЦП% растет, у вас есть какая-то обработка списка, когда список увеличивается с каждым тактом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...