2017-03-16 3 views
1

Queue<string> 개체를 사용하여 파일을 처리하여 항목을 관리하는 서비스를 구축했습니다. 이에 스레드의 수를 제한하는 방법을 연구 하다니DataFlow에서 중복 항목 감지

public partial class BasicQueueService : ServiceBase 
{ 
    private readonly EventWaitHandle completeHandle = 
     new EventWaitHandle(false, EventResetMode.ManualReset, "ThreadCompleters"); 

    public BasicQueueService() 
    { 
     QueueManager = new Queue<string>(); 
    } 

    public bool Stopping { get; set; } 

    private Queue<string> QueueManager { get; } 

    protected override void OnStart(string[] args) 
    { 
     Stopping = false; 

     ProcessFiles(); 
    } 

    protected override void OnStop() 
    { 
     Stopping = true; 
    } 

    private void ProcessFiles() 
    { 
     while (!Stopping) 
     { 
      var count = QueueManager.Count; 
      for (var i = 0; i < count; i++) 
      { 
       //Check the Stopping Variable again. 
       if (Stopping) break; 

       var fileName = QueueManager.Dequeue(); 
       if (string.IsNullOrWhiteSpace(fileName) || !File.Exists(fileName)) 
         continue; 

       Console.WriteLine($"Processing {fileName}"); 

       Task.Run(() => 
        { 
         DoWork(fileName); 
        }) 
        .ContinueWith(ThreadComplete); 
      } 
      if (Stopping) continue; 

      Console.WriteLine("Waiting for thread to finish, or 1 minute."); 
      completeHandle.WaitOne(new TimeSpan(0, 0, 15)); 
      completeHandle.Reset(); 
     } 
    } 

    partial void DoWork(string fileName); 

    private void ThreadComplete(Task task) 
    { 
     completeHandle.Set(); 
    } 

    public void AddToQueue(string file) 
    { 
     //Called by FileWatcher/Manual classes, not included for brevity. 
     lock (QueueManager) 
     { 
      if (QueueManager.Contains(file)) return; 

      QueueManager.Enqueue(file); 
     } 
    } 
} 

이 (내가이 int을 증가와 함께 수동으로 클래스를 시도했지만, 내 코드에서 제대로 감소하지 않는 문제가있다), 나는 가로 질러 온

public partial class BasicDataFlowService : ServiceBase 
{ 
    private readonly ActionBlock<string> workerBlock; 

    public BasicDataFlowService() 
    { 
     workerBlock = new ActionBlock<string>(file => DoWork(file), new ExecutionDataflowBlockOptions() 
     { 
      MaxDegreeOfParallelism = 32 
     }); 
    } 

    public bool Stopping { get; set; } 

    protected override void OnStart(string[] args) 
    { 
     Stopping = false; 
    } 

    protected override void OnStop() 
    { 
     Stopping = true; 
    } 

    partial void DoWork(string fileName); 

    private void AddToDataFlow(string file) 
    { 
     workerBlock.Post(file); 
    } 
} 
: - 내가 달성하기 위해 노력하고있어 자사 더 잘 맞는 것 같아 TPL DataFlow는, 구체적으로 날이 지금 내 서비스 등 프레임 워크 핸들 스레딩/대기,

을 할 수 있습니다

잘 작동합니다. . 그러나 파일이 한번만 TPL DataFlow에 추가되도록하고 싶습니다. Queue을 사용하면 .Contains()을 사용하여 확인할 수 있습니다. TPL DataFlow에 사용할 수있는 메커니즘이 있습니까?

+0

파일을 사용하고 제출하는 것은 무엇이든 그것을 두 번 게시하지 않을 책임이 있습니다. 디렉토리에서 파일을 읽는 경우 태그를 지정할 수 있으며 경로를 @VMAtm 제안대로 캐시 할 수 있습니다. 그러나 사용자 또는 다른 클라이언트가 제출하는 경우 프로세스를 일로 처리해야합니다. 각 파일은 단일 결과가있는 단일 작업을 나타냅니다. – JSteward

답변

0

DoWork에서 확인할 수 있습니다.

Hash에 이미 작업 한 항목을 저장하고 현재 파일 이름이 해시에 존재하지 않는지 확인해야합니다.

1

귀하의 솔루션이 Queue 인 경우는 파일이 짧은 시간 내에 두 번 서비스에 들어갈 경우에만 작동합니다. 다시 말하면 몇 시간이 지나면 대기열에 들어 가지 않습니다. 그곳에는 Dequeue입니다. 이 솔루션이 예상되는 경우

, 당신은 다음과 같이 파일 경로가 이미 처리되고 저장하는 MemoryCache을 사용할 수 있습니다 :

using System.Runtime.Caching; 

private static object _lock = new object(); 

private void AddToDataFlow(string file) 
{ 
    lock (_lock) 
    { 
     if (MemoryCache.Default.Contains(file)) 
     { 
      return; 
     } 

     // no matter what to put into the cache 
     MemoryCache.Default[file] = true; 
    // we can now exit the lock 
    } 

    workerBlock.Post(file); 
} 

그러나, 응용 프로그램 서비스가 의도 된 (오랜 시간 동안 실행해야하는 경우 해야 할 일), 당신은 결국 추방 될 것입니다. 이 경우 파일 경로를 데이터베이스에 저장해야 할 수도 있으므로 서비스를 다시 시작한 후에도 코드가 상태를 복원합니다.