2012-03-12 4 views
2

각 작업을 소비하는 한정된 소비자 스레드 세트가 있습니다. 일단 작업을 처리하면 소모 된 작업에 나열된 하위 작업 목록이 있습니다. 데이터베이스에 아직없는 목록에서 하위 작업을 추가해야합니다. 데이터베이스에 3 백만 개가 있으므로 데이터베이스에없는 목록을 얻는 것이 느립니다. 나는 각 스레드가 해당 호출을 차단하는 것을 신경 쓰지 않지만, 경쟁 조건 (코드 참조)이 있기 때문에 느린 호출에서 모든 코드를 잠궈 야하므로 한 번에 하나씩 만 호출 할 수 있고 프로그램은 크롤링 할 수 있습니다. 이 문제를 해결하기 위해 스레드가 통화를 늦추지 않도록하려면 어떻게해야합니까? 대기열을 시도했지만 컴퓨터가 데이터베이스에 추가해야하는 작업보다 스레드가 작업 목록을 빨리 밀어 내고 있기 때문에 계속 커지고 빈 상태가되지 않는 대기열로 끝납니다.다중 스레드 세트 차이에 대한 효율적인 접근

내 코드 :

IEnumerable<string> getUniqueJobNames(IEnumerable<job> subJobs, int setID) 
{ 
    return subJobs.Select(el => el.name) 
     .Except(db.jobs.Where(el => el.set_ID==setID).Select(el => el.name)); 
} 

//...consumer thread i 
lock(lockObj) 
{ 
    var uniqueJobNames = getUniqueJobNames(consumedJob.subJobs, consumerSetID); 
    //if there was a context switch here to some thread i+1 
    // and that thread found uniqueJobs that also were found in thread i 
    // then there will be multiple copies of the same job added in the database. 
    // So I put this section in a lock to prevent that. 
    saveJobsToDatabase(uniqueJobName, consumerSetID); 
} 
//continue consumer thread i... 
+0

무엇 todo를 시도하고 있습니다, 다시 설명 할 수 있습니까? 수행 할 작업은 무엇입니까? 정보가 없으면 실제 작업이 더 명확 해집니다. – ntziolis

+0

먼저 기존 작업의 목록을 가져온 다음 목록을 컴파일 할 수 없습니까? "새로운"하위 작업을 병행하여 수행하고 마지막으로 새로운 작업을 저장합니까? –

+0

문제는 예외를 사용하여 데이터베이스와 비교하지 않으면 어느 것이 새로운 것인지 알 수 없다는 것입니다. 필자는 모든 하위 작업 목록을 컴파일 할 수 있었지만 마침내 데이터베이스와 비교하기를 원할 때 다음 목록이 나올 때까지 작업을 마칠 수 없었습니다. 그것들은 내가 나중에 목록을 캐싱하거나 즉시 실행할 때 Except 메서드를 실행할 수있는 것보다 빠르게 구축하고 있습니다. 실제로 그것을 즉시 실행하면 소비자가 더 빨리 달리고 이슈가 더 복잡해질 것입니다. 나는 도움이 될 수있는 데이터 구조, 또는 단지 다른 알고리즘을 추측하고 있습니다. – brandon

답변

2

보다는 작업 이름의 고유성을 확인하기 위해 데이터베이스에 다시 가고 그럴 수는 훨씬 더 빨리 존재를 확인할 수 있습니다 메모리에 조회 데이터 구조에 관련 정보 :

Dictionary<int, HashSet<string>> jobLookup = db.jobs.GroupBy(i => i.set_ID) 
    .ToDictionary(i => i.Key, i => new HashSet<string>(i.Select(i => i.Name))); 

이것은 한 번뿐입니다. 당신은 또한 새 하위 작업을 입력 조회에 추가해야하는 경우

IEnumerable<string> getUniqueJobNames(IEnumerable<job> subJobs, int setID) 
{ 
    var existingJobs = jobLookup.ContainsKey(setID) ? jobLookup[setID] : new HashSet<string>(); 

    return subJobs.Select(el => el.Name) 
     .Except(existingJobs); 
} 

: 이후 고유성을 확인해야 할 때마다 당신은 조회를 사용 그것이 나에게 분명하지 않다

lock(lockObj) 
{ 
    var uniqueJobNames = getUniqueJobNames(consumedJob.subJobs, consumerSetID); 
    //if there was a context switch here to some thread i+1 
    // and that thread found uniqueJobs that also were found in thread i 
    // then there will be multiple copies of the same job added in the database. 
    // So I put this section in a lock to prevent that. 
    saveJobsToDatabase(uniqueJobName, consumerSetID); 

    if(!jobLookup.ContainsKey(newconsumerSetID)) 
    { 
     jobLookup.Add(newconsumerSetID, new HashSet<string>(uniqueJobNames)); 
    } 
    else 
    { 
     jobLookup[newconsumerSetID] = new HashSet<string>(jobLookup[newconsumerSetID].Concat(uniqueJobNames))); 
    } 
} 
+0

좋은 해결책. 매번 NlogN 검색을하는 것보다 훨씬 좋은 메모리를 사용합니다. 새로운 데이터를 데이터베이스와 동기화하는이 데이터 구조의 사용자 정의 버전을 작성하겠습니다. – brandon

+0

제 제안은 데이터 구조를 지나치게 복잡하게 만들지 않고 DB/메모리를 별도로 처리하여 디버깅 문제를 훨씬 간단하게 만듭니다. – ntziolis

관련 문제