想要将流程转换为多线程流程

时间:2010-01-05 17:19:50

标签: java multithreading concurrency

让我回顾一下我的代码正在做什么(还没编码),我想让它在多个线程中运行以加快速度。

  1. 在数据库中查找尚未处理的记录:

    SELECT TOP 1 * FROM Products WHERE isActive = 1
    
  2. 查找URL(Rest调用),返回HTML并将其存储在数据库中

  3. 设置该行的标志:

    UPDATE Products SET isActive = 0 WHERE rowId = 234
    
  4. 所以说我将上面的内容包装成一个方法:

    public void UpdateProduct()
    {
    }
    

    是否可以在多个线程中运行此进程? (比如2或3)?

    更新的 有人能告诉我如何将这个方法包装成多线程进程的骨架结构吗?

5 个答案:

答案 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;
  }
}

UpdateItemObtainNextItem(从调用到syncData)中,互斥锁的双重锁定仍然有一些细微的问题需要解决,但在翻译成真实的时候很容易修复实施

答案 2 :(得分:1)

SELECT TOP 1 * FROM Products WHERE isActive = 1 

可能导致表扫描,并且在这种情况下一次只返回一行是浪费服务器的资源。最好一次返回前10名(甚至更多基于你的应用程序)并且只是对内存数据进行并发检索,就像wallyk指出的那样。

答案 3 :(得分:0)

假设您正在使用支持并发的外部数据库,这应该没问题。您可能希望使用行级锁定来防止线程使用相同的数据,以及一些有助于每个线程选择不同数据进行操作的算法。

答案 4 :(得分:0)

最简单的方法可能是设置线程池并使用行加载线程安全队列。

然后,每个“池线程”将首先抓取队列中的顶级记录(将其从队列中弹出,以便其他线程也不能获取相同的记录),下载HTML并更新记录。 / p>