我有一个应用程序,它有三个线程。哪个访问单个数据表。 每个线程一次打印一行。它不应该重复。但在我的应用程序中,所有三个线程都打印出来自datatable的所有行。
我希望一行只打印一次。
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
{}
}
}
答案 0 :(得分:1)
<强>第一强>
为什么要在每个线程中重新执行“SQLite.ExecuteQuery
”?如果您只想在不阻止UI的情况下打印表中的所有行,则只需要一个单个后台Thread
来执行查询,然后打印行。
有更多的线程试图从相同的数据库读取并尝试写入相同的 Console
,可能会降低应用程序的速度而不是加快速度(因为执行的时间是相同的,但你必须总结线程之间所有上下文切换所需的时间。)
<强> SECOND 强>
好的,假设您仍需要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]
不同!它们是单独的对象,因此锁定部分不会阻止任何其他线程的执行!
<强> THIRD 强>
“if (dt.Rows.Count != 0)
”语句完全没用。
当您输入for
循环,并且没有行时,循环会在第一次检查时退出而没有后果。
在for / foreach循环之前有意义的检查是针对空列表的检查。所以你可以写:
“if (Rows != null) { for (int i = 0; i < Rows.Count; i++) { ... ... ... }
”
<强>更新强>
如果您只需要将行打印到控制台,则可以有1000个线程,但由于它们都打印到同一个控制台,因此您有999个无用的线程。如果您必须在一行上执行某些“昂贵”操作并且然后将其显示到控制台,则情况会有所不同。在这种情况下,试试这个:
startRow
和endRow
数字。该方法仅使用这些行创建DataTable,并仅将这些行打印到控制台。无论如何,此解决方案不会按顺序打印所有行。这是一项要求吗?