winforms C # .NET - Döngüleri kullanırken kodumun Performansını Nasıl Artırırım (for, foreach, vb ...) [kapalı]
Üniversiteler için bir uygulama geliştiriyorum, uygulamanın bir parçası da haftalık ders programını ayarlamaktır.
Benim parametrelerim Sınıf numarası, Haftanın Günü ve Zaman Aralığı'dır.
Yani bir dizi sınıfım var, her sınıfın bir numarası var.
Çalışma Zamanında, uygulama veritabanımda kaç tane sınıfım olduğuna bağlı olarak bazı düğmeler oluşturur ve her Düğmede sınıf numaraları belirler.
Yapmak istediğim, her Sınıf düğmesini "Kırmızı" Arka Renk ile Etiketlemek, eğer söz konusu sınıf belirli Haftanın Gününde ve verilen Zaman Aralığında doluysa.
Yapmak istediğimi başardım ve kodum hatasız çalışıyor, ancak şimdi tek sorunum performans.
İşte benim Kodum:
private OleDbConnection Connection = new OleDbConnection();
private void SomeMethod(string Day, string Time)
{
int MaxIndex = 0;
string str1 = "select Max([Row Index]) from Table";
OleDbCommand Command1 = new OleDbCommand(str1, Connection);
Connection.Open();
if (Command1.ExecuteScalar() == DBNull.Value)
MaxIndex = 1;
else
MaxIndex = Convert.ToInt32(Command1.ExecuteScalar());
Connection.Close();
for (int i = 0; i < MaxIndex; i++)
{
string str = "select [classroom Number] from Table where [Day] = @ParamDay and [Time] = @ParamTime and [Row Index] = @ParamIndex";
OleDbCommand Command = new OleDbCommand(str, Connection);
Command.Parameters.Add("@ParamDay", Day);
Command.Parameters.Add("@ParamTime", Time);
Command.Parameters.Add("@ParamIndex", i + 1);
Connection.Open();
OleDbDataReader reader = Command.ExecuteReader();
if (reader.Read())
{
foreach (Button btn in ButtonsPanel.Controls)
{
if (btn.Text == reader["classroom Number"].ToString())
{
btn.BackColor = Color.Red;
}
}
Connection.Close();
}
}
}
Bu nedenle, sahip olmayı beklediğim 200 satırım varsa bu kod yaklaşık 13 saniye sürer.
Soru şu ... Koduma yapabileceğim bir şey var mı ki bu 13 saniyenin en az 2-4 saniyeye düşmesi için?
Bilgi için: İnternette çok araştırdım ama sorunumun çözümünü burada bulamadım.
Yanıtlar
For döngüsüne hiç ihtiyacınız yok gibi görünüyor. Ve MaxIndex
ikisi de. Sadece zaman ve işaret düğmeleri için kayıtları indirin.
private void SomeMethod(string Day, string Time)
{
HashSet<string> classNumbers = new HashSet<string>();
string str = "select [classroom Number] from Table where [Day] = @ParamDay and [Time] = @ParamTime";
using (OleDbCommand Command = new OleDbCommand(str, Connection))
{
Command.Parameters.Add("@ParamDay", Day);
Command.Parameters.Add("@ParamTime", Time);
Connection.Open();
using (OleDbDataReader reader = Command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
classNumbers.Add(reader["classroom Number"].ToString());
}
}
}
foreach (Button btn in ButtonsPanel.Controls)
{
if (classNumbers.Contains(btn.Text))
{
btn.BackColor = Color.Red;
}
}
}
İyileştirmek için değiştirebileceğiniz iki şey vardır:
- Bağlantıyı yalnızca bir kez açıp kapatın, bu da kod çalışma süresini kısaltabilir.
- İşlemek istediğiniz tüm verileri tek bir sorguda alın.
Aşağıdaki koda bakın:
private OleDbConnection Connection = new OleDbConnection();
private void SomeMethod(string Day, string Time)
{
int MaxIndex = 0;
string str1 = "select Max([Row Index]) from Table";
OleDbCommand Command1 = new OleDbCommand(str1, Connection);
Connection.Open();
if (Command1.ExecuteScalar() == DBNull.Value)
MaxIndex = 1;
else
MaxIndex = Convert.ToInt32(Command1.ExecuteScalar());
string str = "select [classroom Number] from Table where [Day] = @ParamDay and [Time] = @ParamTime and [Row Index] between 1 and @ParamIndex";
OleDbCommand Command = new OleDbCommand(str, Connection);
Command.Parameters.Add("@ParamDay", Day);
Command.Parameters.Add("@ParamTime", Time);
Command.Parameters.Add("@ParamIndex", MaxIndex);
OleDbDataReader reader = Command.ExecuteReader();
while (reader.Read())
{
foreach (Button btn in ButtonsPanel.Controls)
{
if (btn.Text == reader["classroom Number"].ToString())
{
btn.BackColor = Color.Red;
}
}
}
Connection.Close();
}
Yorumlarıma göre, sorguyu yalnızca bir kez yürütmeniz ve sonuç kümesinde döngü yapmanız gerekir. IO genellikle çok yavaş olduğundan, artık IO'ya yalnızca bir kez eriştiğiniz için bu, performans kazanımları sağlayacaktır.
İşte bir örnek (test edilmemiş):
private void SomeMethod(string day, string time)
{
// Using statement helps to dispose any resources once done with the connection
// connectionString can be any string that opens your database
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
// The query has removed the notion of index, it will just get all the data for that day and time
string query = "SELECT [classroom Number] FROM Table WHERE [Day] = @ParamDay AND [Time] = @ParamTime";
// Since OleDbCommand inherits from IDisposable, use a using statement
using (OleDbCommand command = new OleDbCommand(query, connection))
{
// Notice how we don't use index anymore
command.Parameters.Add("@ParamDay", day);
command.Parameters.Add("@ParamTime", time);
// Open connection here, don't need to close connection
connection.Open();
// Since OleDbDataReader inherits from IDisposable, use a using statement
using (OleDbDataReader reader = command.ExecuteReader())
{
// We're now looping through all the rows in the result set
while (reader.Read())
{
UpdateButtonColor(reader["classroom Number"].ToString());
}
}
}
}
}
private void UpdateButtonColor(string classroomNumber)
{
foreach (Button btn in ButtonsPanel.Controls)
{
if (btn.Text == classroomNumber)
{
btn.BackColor = Color.Red;
}
}
}
Daha yeni C # sürümleri, using
ifadenin küme parantezleri gerektirmemesine izin verir (bu da iç içe geçmeyi azaltır), bu da şöyle görünür:
private void SomeMethod(string day, string time)
{
string query = "SELECT [classroom Number] FROM Table WHERE [Day] = @ParamDay AND [Time] = @ParamTime";
using OleDbConnection connection = new OleDbConnection(connectionString);
using OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add("@ParamDay", day);
command.Parameters.Add("@ParamTime", time);
connection.Open();
using OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
UpdateButtonColor(reader["classroom Number"].ToString());
}
}
Bunun için belgeler bulunabilir burada