Java 具有循环引用的大型图的并行爬行
简而言之:我想以并行方式处理带有循环引用的大型图。而且我也无法访问完整的图形,我必须在其中爬行。我想组织有效的队列来做到这一点。我很感兴趣,有什么最佳实践可以做到这一点吗 我试图为这样的策略组织无限的数据处理流:每个线程从队列中提取节点进行处理,在处理之后进行处理—可能会出现一些新的处理节点—所以线程必须将它们放入队列中。但我不必对每个节点进行多次处理。节点是不可变的实体 据我所知,我必须使用队列和集合的一些线程安全实现(对于已经访问过的实例) 我试图避免使用同步方法。因此,我对该流程的实现:Java 具有循环引用的大型图的并行爬行,java,multithreading,algorithm,concurrency,graph-theory,Java,Multithreading,Algorithm,Concurrency,Graph Theory,简而言之:我想以并行方式处理带有循环引用的大型图。而且我也无法访问完整的图形,我必须在其中爬行。我想组织有效的队列来做到这一点。我很感兴趣,有什么最佳实践可以做到这一点吗 我试图为这样的策略组织无限的数据处理流:每个线程从队列中提取节点进行处理,在处理之后进行处理—可能会出现一些新的处理节点—所以线程必须将它们放入队列中。但我不必对每个节点进行多次处理。节点是不可变的实体 据我所知,我必须使用队列和集合的一些线程安全实现(对于已经访问过的实例) 我试图避免使用同步方法。因此,我对该流程的实现:
public class ParallelDataQueue {
private LinkedBlockingQueue<String> dataToProcess = new LinkedBlockingQueue<String>();
// using map as a set
private ConcurrentHashMap<String, Object> processedData = new ConcurrentHashMap<String, Object>( 1000000 );
private final Object value = new Object();
public String getNextDataInstance() {
while ( true ) {
try {
String data = this.dataToProcess.take();
Boolean dataIsAlreadyProcessed = ( this.processedData.putIfAbsent( data, this.value ) != null );
if ( dataIsAlreadyProcessed ) {
continue;
} else {
return data;
}
} catch ( InterruptedException e ) {
e.printStackTrace();
}
}
}
public void addData( Collection<String> data ) {
for ( String d : data ) {
if ( !this.processedData.containsKey( d ) ) {
try {
this.dataToProcess.put( d );
} catch ( InterruptedException e ) {
e.printStackTrace();
}
}
}
}
}
公共类并行数据队列{
私有LinkedBlockingQueue dataToProcess=新LinkedBlockingQueue();
//使用地图作为集合
私有ConcurrentHashMap processedData=新ConcurrentHashMap(1000000);
私有最终对象值=新对象();
公共字符串getNextDataInstance(){
while(true){
试一试{
字符串数据=this.dataToProcess.take();
布尔值dataIsAlreadyProcessed=(this.processedData.putIfAbsent(data,this.value)!=null);
如果(数据isalreadyprocessed){
继续;
}否则{
返回数据;
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公共数据(收集数据){
for(字符串d:数据){
如果(!this.processedData.containsKey(d)){
试一试{
this.dataToProcess.put(d);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
}
}
所以我的问题是,当前的实现是否避免了对可重复节点的处理。也许还有更优雅的解决方案
谢谢
p.S.
我理解,这样的实现并不能避免队列中节点的重复出现。但对我来说,这并不重要——我所需要的只是避免对每个节点进行多次处理。您当前的实现无法避免重复的数据实例。假设“线程A”检查并发映射中是否存在数据,并发现数据不存在,所以它将报告数据不存在。但就在执行if after putIfAbsent行之前,“线程A”被挂起。此时,另一个威胁“线程B”,计划由cpu执行,并检查同一数据元素的存在,发现它不存在,并报告为不存在,并将其添加到队列中。当线程A被重新调度时,它将从if行继续,并再次将其添加到队列中。是。使用
ConcurrentLinkedQueue
()
也
当线程向队列添加数据时,它会检查每个数据实例:如果集合包含此数据的实例,则线程不会将其添加到队列。但这还不是全部
不是线程安全的方法,除非基础集合是线程安全的。(这意味着它在内部是同步的)但是检查是没有意义的,因为它已经是线程安全的了。如果你需要以多线程的方式处理数据,你可能根本不需要集合。你没有想过使用Executors框架吗
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newFixedThreadPool(100);
while (true) { // provide data ininitely
for (int i = 0; i < 1000; i++)
exec.execute(new DataProcessor(UUID.randomUUID(), exec));
Thread.sleep(10000); // wait a bit, then continue;
}
}
static class DataProcessor implements Runnable {
Object data;
ExecutorService exec;
public DataProcessor(Object data, ExecutorService exec) {
this.data = data;
this.exec = exec;
}
@Override
public void run() {
System.out.println(data); // process data
if (new Random().nextInt(100) < 50) // add new data piece for execution if needed
exec.execute(new DataProcessor(UUID.randomUUID(), exec));
}
}
publicstaticvoidmain(String[]args)抛出InterruptedException{
ExecutorService exec=Executors.newFixedThreadPool(100);
while(true){//提供不完整的数据
对于(int i=0;i<1000;i++)
exec.execute(新的数据处理器(UUID.randomuid(),exec));
Thread.sleep(10000);//稍等,然后继续;
}
}
静态类DataProcessor实现可运行{
对象数据;
服务执行人;
公共数据处理器(对象数据,ExecutorService exec){
这个数据=数据;
this.exec=exec;
}
@凌驾
公开募捐{
System.out.println(数据);//进程数据
if(new Random().nextInt(100)<50)//如果需要,添加新的数据块以执行
exec.execute(新的数据处理器(UUID.randomuid(),exec));
}
}
我理解,这样的实现并不能避免队列中出现重复的数据。但对我来说,这并不重要——我所需要的只是避免多次处理每个数据实例。方法getNextDataInstance()不会返回已处理的数据。还是我错了?那应该没问题。HashMap是检测集合中是否存在项的最快方法之一。请描述一下ConcurrentLinkedQueue在这种情况下如何帮助我。是的,当然我使用的是执行器,但我也需要避免多次处理相同的数据。“相同的数据”是什么意思?是data1.equals(data2)还是data1==data2?无论如何,在这两种情况下,我担心在数据处理之外的设计会有问题。因为(当然,IMHO)跟踪数据是数据提供商的责任。或者,您可能不需要在中处理一段数据