在 C# 中的多线程中共享单个数据表

Share Single Datatable in Multi Threading in C#

我有一个应用程序,它有三个线程。访问单个数据表。 每个线程一次打印一行。它不应该 repeat.but 在我的应用程序中,所有三个线程都打印数据表中的所有行。

我希望一行只打印一次。

   class Program
    {
        static void Main(string[] args)
        {
            ThreadStart testThread1Start = new ThreadStart(new program().testThread1);
            ThreadStart testThread2Start = new ThreadStart(new Program().testThread2);

            Thread[] testThread = new Thread[2];
            testThread[0] = new Thread(testThread1Start);
            testThread[1] = new Thread(testThread2Start);

            foreach (Thread myThread in testThread)
            {
                myThread.Start();
            }
            Console.ReadLine();
        }

        private void testThread2()
        {          
            DataTable dt = SQLite.ExecuteQuery("SELECT id,name,address FROM example ");
            if (dt.Rows.Count != 0)
            {            
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    lock (dt.Rows[i])
                    {
                        var Id = dt.Rows[i]["Id"].ToString();
                        SQLite.ExecuteNonQuery("update example set DisplayDataStatus = 1 where id= '" + Id + "' ");
                        var name = dt.Rows[i]["name"].ToString();
                        var address = dt.Rows[i]["address"].ToString();
                        Console.WriteLine("ID:"+Id+"|Name:"+name+"|address:"+adress);
                    }
                    Console.ReadLine();
                }
            }
            else
            {}
        }

        private void testThread1()
        {
            DataTable dt = SQLite.ExecuteQuery("SELECT id,name,address FROM example ");
            if (dt.Rows.Count != 0)
            {            
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    lock (dt.Rows[i])
                    {
                        var Id = dt.Rows[i]["Id"].ToString();
                        SQLite.ExecuteNonQuery("update example set DisplayDataStatus = 1 where id= '" + Id + "' ");
                        var name = dt.Rows[i]["name"].ToString();
                        var address = dt.Rows[i]["address"].ToString();
                        Console.WriteLine("ID:"+Id+"|Name:"+name+"|address:"+adress);
                    }
                    Console.ReadLine();
                }
            }
            else
            {}
        }
    }

第一个

为什么要在每个线程中重新执行“SQLite.ExecuteQuery”?如果只想打印table中的所有行而不阻塞UI,有一个后台执行查询就够了Thread然后打印行。 让更多线程尝试从 same 数据库读取并尝试写入 same Console,反而会减慢您的应用程序加快它的速度(因为执行时间是相同的,但你必须总结线程之间所有上下文切换所需的时间)。

第二个

好的,假设你还需要3个线程来执行其他并行操作。

假设 DataTable 实例对于所有线程都是相同的。 Row 上的锁仅阻止线程同时写入 Row 。假设 Thread T1 正在写 Row R1。 T2 在 R1 上被阻塞,无法写入。然后 T1 完成,解锁 R1 并阻止 R2。因为现在R1已经解封,T2进入R1的lock段写入R1。等等。所以所有线程都写入所有行,但在不同的时刻。

假设每个 Thread 都像您的代码那样创建自己的 DataTable。如果 T1 锁定 dt.Row[0],那与 T2 的 dt.Row[0] 不是同一个对象!它们是独立的对象,因此锁定部分不会阻止任何其他线程的执行!

第三

if (dt.Rows.Count != 0)”语句完全没用。 当您进入 for 循环并且没有行时,循环会在第一次检查时退出而不会产生任何后果。

在 for/foreach 循环之前有意义的检查是针对空列表的检查。所以你可以这样写:

"if (Rows != null) { for (int i = 0; i < Rows.Count; i++) { ... ... ... }"

更新

如果您只需要将行打印到控制台,您可以有 1000 个线程,但由于它们都打印到同一个控制台,所以您有 999 个无用线程。如果您必须对一行执行某些 "expensive" 操作,然后 然后 将其显示到控制台,情况就不同了。在这种情况下,试试这个:

  • 执行仅检索行计数的查询。
  • 根据总计数将所有行分为三个范围,为每个线程分配一个范围并启动每个线程。例如T1只查询0-14999行,T2查询15000-29999行,以此类推。
  • 传递给每个线程的方法可以相同,但输入的 startRowendRow 数字不同。该方法仅使用这些行创建一个 DataTable,并仅将这些行打印到控制台。

无论如何,此解决方案不会按顺序打印所有行。这是要求吗?