什么是多线程的最佳方式?

时间:2016-08-15 05:57:58

标签: c# sql database multithreading

我的申请有点问题。 我有一个数据库编辑器,当我尝试更新数据库文件时,它有时会挂起。并非每次,但经常,并且每次在数据库发生任何更改之前发生。我认为这是因为没有使用多线程。我最近才开始学习编程,即使阅读了一些多线程解释,我也有点迷失。有人可以向我解释我应该如何在我的具体例子中实现它?

    private void adjustStatsButton_Click(object sender, EventArgs e)
    {
            ReadWrite.AdjustStats(winnerInput.Text, loserInput.Text);
            winnerInput.Text = "";
            loserInput.Text = "";
            Refresh(leaderboardBox);
    }

    public class ReadWrite
    {
        public static void AdjustStats(string winner, string loser)
        {
            SQLiteConnection dbConnection = new SQLiteConnection("Data Source = Leaderboards.sqlite; Version = 3");

string sql = "SELECT * FROM leaderboard WHERE name='" + winner + "'"; SQLiteCommand command = new SQLiteCommand(sql, dbConnection); dbConnection.Open(); SQLiteDataReader reader = command.ExecuteReader(); double wrating = Convert.ToDouble(reader["rating"]); int wmatches = Convert.ToInt32(reader["matches"]); int wwins = Convert.ToInt32(reader["wins"]); sql = "SELECT * FROM leaderboard WHERE name='" + loser + "'"; command = new SQLiteCommand(sql, dbConnection); reader = command.ExecuteReader(); double lrating = Convert.ToDouble(reader["rating"]); int lmatches = Convert.ToInt32(reader["matches"]); int lwins = Convert.ToInt32(reader["wins"]); int llosses = Convert.ToInt32(reader["losses"]); double RC = (1 - ((wrating - lrating) / 200)) * 8; if (RC < 0) RC *= -1; if (RC < 4) RC = 4; else if (RC > 12) RC = 12; wmatches++; wwins++; lmatches++; llosses++; wrating += RC; if (wrating < 0) wrating = 0; lrating -= RC; if (lrating < 0) lrating = 0; double wwinrate = Convert.ToDouble(wwins) / wmatches; double lwinrate = Convert.ToDouble(lwins) / lmatches; sql = "UPDATE leaderboard SET rating=" + wrating + ", matches=" + wmatches + ", wins=" + wwins + ", winrate=" + wwinrate + " WHERE name='" + winner + "'"; command = new SQLiteCommand(sql, dbConnection); command.ExecuteNonQuery(); sql = "UPDATE leaderboard SET rating=" + lrating + ", matches=" + lmatches + ", losses=" + llosses + ", winrate=" + lwinrate + " WHERE name='" + loser + "'"; command = new SQLiteCommand(sql, dbConnection); command.ExecuteNonQuery(); dbConnection.Close(); } }

3 个答案:

答案 0 :(得分:0)

您只需要在c#代码中使用async await关键字,它最终会导致异步调用数据库我对您的代码进行了更改:

private async void adjustStatsButton_Click(object sender, EventArgs e)
    {
            await ReadWrite.AdjustStats(winnerInput.Text, loserInput.Text);
            winnerInput.Text = "";
            loserInput.Text = "";
            Refresh(leaderboardBox);
    }


    public class ReadWrite
        {
            public static Task AdjustStats(string winner, string loser)
            {
    return Task.Run(() => 
    {
       SQLiteConnection dbConnection = new SQLiteConnection("Data Source = Leaderboards.sqlite; Version = 3");


            string sql = "SELECT * FROM leaderboard WHERE name='" + winner + "'";
            SQLiteCommand command = new SQLiteCommand(sql, dbConnection);
            dbConnection.Open();
            SQLiteDataReader reader = await command.ExecuteReaderAsync();


            double wrating = Convert.ToDouble(reader["rating"]);
            int wmatches = Convert.ToInt32(reader["matches"]);
            int wwins = Convert.ToInt32(reader["wins"]);

            sql = "SELECT * FROM leaderboard WHERE name='" + loser + "'";
            command = new SQLiteCommand(sql, dbConnection);
            reader = await command.ExecuteReaderAsync();

            double lrating = Convert.ToDouble(reader["rating"]);
            int lmatches = Convert.ToInt32(reader["matches"]);
            int lwins = Convert.ToInt32(reader["wins"]);
            int llosses = Convert.ToInt32(reader["losses"]);

            double RC = (1 - ((wrating - lrating) / 200)) * 8;
            if (RC < 0) RC *= -1;
            if (RC < 4) RC = 4;
            else if (RC > 12) RC = 12;

            wmatches++;
            wwins++;
            lmatches++;
            llosses++;
            wrating += RC;
            if (wrating < 0) wrating = 0;
            lrating -= RC;
            if (lrating < 0) lrating = 0;
            double wwinrate = Convert.ToDouble(wwins) / wmatches;
            double lwinrate = Convert.ToDouble(lwins) / lmatches;

            sql = "UPDATE leaderboard SET rating=" + wrating + ", matches=" + wmatches + ", wins=" + wwins + ", winrate=" + wwinrate + " WHERE name='" + winner + "'";
            command = new SQLiteCommand(sql, dbConnection);
            await command.ExecuteNonQueryAsync();

            sql = "UPDATE leaderboard SET rating=" + lrating + ", matches=" + lmatches + ", losses=" + llosses + ", winrate=" + lwinrate + " WHERE name='" + loser + "'";
            command = new SQLiteCommand(sql, dbConnection);
            await command.ExecuteNonQueryAsync();
            dbConnection.Close();
            }
});

        }

答案 1 :(得分:0)

问题是您在UI线程中运行查询。以下是使用this example启发 if ($_POST["a"] != "" || $_POST["b"] != "") { [proceed....] } 重度并使用Arguments的示例。这样它将在一个单独的线程中运行,它不会锁定GUI。

BackgroundWorker

您的实施:

// Class for passing arguments
public class BqArguments
{
    public string Winner {get;set}
    public string Loser {get;set}
}

答案 2 :(得分:0)

您的问题的核心是您在UI线程上调用阻塞(同步)数据库调用。这会阻止你的UI线程在等待数据库时,而不是保持响应良好。

在一般情况下,由于这些是基于I / O的操作,因此能够使它们自然地异步,如Lakhtey's answer所示。 但是,SQLite不支持实际的异步操作。 :(

因此,在这种情况下,最好的办法是将数据库工作包装到后台线程中。请注意,使用 YEAR MONTH 2012 1 2012 1 2013 10 2012 2 2014 7 远远优于if month = 1 then date = input(compress("01/01/"||year),mmddyy10.); else if month = 2 then date = input(compress("02/01/"||year),mmddyy10.); ...

Task.Run