让我回顾一下我的代码正在做什么(还没编码),我想让它在多个线程中运行以加快速度。
在数据库中查找尚未处理的记录:
SELECT TOP 1 * FROM Products WHERE isActive = 1
查找URL(Rest调用),返回HTML并将其存储在数据库中
设置该行的标志:
UPDATE Products SET isActive = 0 WHERE rowId = 234
所以说我将上面的内容包装成一个方法:
public void UpdateProduct()
{
}
是否可以在多个线程中运行此进程? (比如2或3)?
更新的 有人能告诉我如何将这个方法包装成多线程进程的骨架结构吗?
答案 0 :(得分:3)
SELECT TOP 1 * FROM Products WHERE isActive = 1
这将是一个问题。在处理Top 1之前,所有线程都将检索相同的记录。我建议更改此查询以选择产品并在SAME sql调用中将其更新为isActive = 2。这可以使用存储过程或匿名开始/结束块来完成。每次通话都会收到一份独特的记录。
除此之外,你还是金色的。
附录:根据建议,如果线程失败或被锁定,可以指定超时,这将允许另一个线程在以后接收并处理。
答案 1 :(得分:3)
由于最慢的活动是html检索,因此可以使用20,50或甚至200个检索线程线性加速,具体取决于ISP带宽相对于返回数据的服务器的速度。
将表半虚拟化为内存数组是明智的。因此,寻找工作的每个线程将查询一个类成员函数,该函数返回下一个可用行或处理完成后更新它。如果有其他更新程序,并且每隔几秒或几分钟将内存中的更新重新发送回d / b,该类还应偶尔检测数据库更新。
我不懂Java,所以这里是PHPish术语中的印象派算法:
class virtualProduct {
const time_t maxSync = 10; // maximum age for unsynched d/b to row[]
static struct { // singleton
int isActive;
int urlRowId;
etc ...
} row [];
static time_t lastSync; // timestamp of last sync with d/b
static mutex theLock; // mutex to protect read/write of above
function syncData()
{
lock (&theLock);
// flush local updates to d/b
foreach (row as item)
if (item.updated)
{
sql_exec ("update products set whatever = " + value + " where rowId = " + whatever);
if (okay)
item .updated = false;
}
// update from d/b (needed if other entities are updating it)
sql_query ("select * from products");
row [] = sql results;
lastSync = now();
unlock (&theLock);
}
function virtualProduct () // constructor
{
...
syncData(); // initialize memory copy of d/b
}
function ~virtualProduct () // destructor
{
syncData(); // write last updates
...
}
function UpdateItem(int id)
{
lock (&theLock);
if (now () - lastSync > maxSync)
syncData();
int index = row.find (id);
if (index >= 0)
{
row [index] .fields = whatever;
row [index] .isActive = 0;
}
unlock (&theLock);
}
function ObtainNextItem()
{
lock (&theLock);
if (now () - lastSync > maxSync)
syncData();
result = null;
foreach (row as item)
if (item.isActive == 1)
{
item.isActive = 2; // using Peter Schuetze's suggestion
result = item.id;
break;
}
unlock (&theLock);
return result;
}
}
在UpdateItem
和ObtainNextItem
(从调用到syncData
)中,互斥锁的双重锁定仍然有一些细微的问题需要解决,但在翻译成真实的时候很容易修复实施
答案 2 :(得分:1)
SELECT TOP 1 * FROM Products WHERE isActive = 1
可能导致表扫描,并且在这种情况下一次只返回一行是浪费服务器的资源。最好一次返回前10名(甚至更多基于你的应用程序)并且只是对内存数据进行并发检索,就像wallyk指出的那样。
答案 3 :(得分:0)
假设您正在使用支持并发的外部数据库,这应该没问题。您可能希望使用行级锁定来防止线程使用相同的数据,以及一些有助于每个线程选择不同数据进行操作的算法。
答案 4 :(得分:0)
最简单的方法可能是设置线程池并使用行加载线程安全队列。
然后,每个“池线程”将首先抓取队列中的顶级记录(将其从队列中弹出,以便其他线程也不能获取相同的记录),下载HTML并更新记录。 / p>