2012-07-03 4 views
1

다음 코드가 있습니다. 여러 스레드에서 파일 생성을 시작하고 싶습니다. 목적은 여러 스레드에서 할 때 10 개의 파일을 만드는 데 시간이 덜 걸린다는 것입니다. 내가 이해할 수 있도록 비동기 호출 요소를 도입해야합니다.멀티 스레딩 및 스피드 업

이 코드 조각을 어떻게 변경해야합니까? 나는 코드의 쓰레드 생성 부분을 언급 단지 루프에서 testMethod 10 번 호출하는 경우

using System; 
using System.Text; 
using System.Threading; 
using System.IO; 
using System.Diagnostics; 

namespace MultiDemo 
{ 
    class MultiDemo 
    { 
     public static void Main() 
     { 
      var stopWatch = new Stopwatch(); 
      stopWatch.Start(); 
      // Create an instance of the test class. 
      var ad = new MultiDemo(); 

      //Should create 10 files in a loop. 
      for (var x = 0; x < 10; x++) 
      { 
       var y = x; 
       int threadId; 
       var myThread = new Thread(() => TestMethod("outpFile", y, out threadId)); 
       myThread.Start(); 
       myThread.Join(); 
       //TestMethod("outpFile", y, out threadId); 
      } 
      stopWatch.Stop(); 
      Console.WriteLine("Seconds Taken:\t{0}",stopWatch.Elapsed.TotalMilliseconds); 
     } 

     public static void TestMethod(string fileName, int hifi, out int threadId) 
     { 
      fileName = fileName + hifi; 
      var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); 
      var sw = new StreamWriter(fs, Encoding.UTF8); 
      for (int x = 0; x < 10000; x++) 
       { 
        sw.WriteLine(DateTime.Now.ToString()); 
       } 
      sw.Close(); 
      threadId = Thread.CurrentThread.ManagedThreadId; 
      Console.WriteLine("{0}",threadId); 
     } 
    } 
} 

는 지금, 그것은 스레드의 생성을 처리하기 위해 시도하는 여러 스레드보다 빠릅니다.

+0

최상의 병렬 구현이 아니며 동일한 실제 디스크에 IO 제한 쓰기가 계속 될 것입니다. TPL을 사용하면 CPU에 더 적합합니다 (현재 컴퓨터에 더 많은 코어가 있음). 동일한 물리적 디스크의 디스크 입출력은 직렬입니다 (일부 캐싱 있음). – Paparazzi

+0

이미 mutithreaded 파일 복사/생성을 구현 한 vxCopy http://www.vrxtools.com/vxcopy/Default.aspx를 살펴보십시오. 어쩌면 당신은 그것으로부터 약간의 아이디어를 얻을 수 있습니다. – ja72

답변

0

가 여기 병렬 작업을 위해 멀티 스레딩, 속도를 얻을 수있는 잘못된 방법입니다,하지만 아마도이 직접 질문에 대답하지 않습니다

1

을 가속화 할뿐만하면 문제에 대한 내 생각이다. 이 코드의 병목 현상은 프로세서가 될 것 같지 않습니다. 나는 디스크 IO가 way보다 CPU 처리 시간이 더 걸릴 것이라고 확신합니다. 따라서, 나는 새로운 스레드를 만드는 것이 전혀 도움이되지 않는다고 믿는다. (모든 스레드는 같은 디스크에 쓰기를 시도 할 것이다.) 나는 이것이 조숙 한 최적화의 경우라고 생각한다. 내가 너라면, 내가 한 스레드에서 다 할거야.

+0

사실, 계속 진행하기 전에 모든 스레드가 완료 될 때까지 기다리지 않으면 더 나은 메트릭을 얻을 수 있습니다. –

0

왜 멀티 스레딩을 사용하기로 결정 했습니까? 새 스레드를 시작하는 가격은 단순한 루프보다 높을 수 있습니다. 맹목적으로 결정할 수있는 것이 아닙니다 ... 스레드 사용을 주장하는 경우 관리 된 ThreadPool/사용량이 async delegates인지 확인할 수 있습니다. 기존 스레드를 다시 사용하여 새 스레드 생성 비용을 줄일 수 있습니다.

5

코드의 스레드 버전은 추가 작업을 수행하므로 속도가 더 느리다는 것은 놀라운 일이 아닙니다.

당신은 같은 것을 할 때 :

var myThread = new Thread(() => TestMethod("outpFile", y, out threadId)); 
myThread.Start(); 
myThread.Join(); 

이 ... 당신이 종료 될 때까지 다음을 기다리고, 그것은 TestMethod를 호출하도록, 스레드를 만들합니다. 스레드를 만들고 시작하는 데 따른 추가 오버 헤드로 인해 스레드가없는 TestMethod을 호출하는 것보다 속도가 느려집니다.

그것은 당신이 모든 스레드가 작업하고 종료 될 때까지 기다립니다 시작하면 당신은 더 나은 성능을 볼 수있을 가능성 예 :

var workers = new List<Thread>(); 
for (int i = 0; i < 10; ++i) 
{ 
    var y = x; 
    int threadId; 
    var myThread = new Thread(() => TestMethod("outpFile", y, out threadId)); 
    myThread.Start(); 
    workers.Add(myThread); 
} 
foreach (var worker in workers) worker.Join(); 
0

여러 스레드의 이익을 부정하고 당신 때문에 Join 각 스레드와 다음 스레드를 만들고 시작하기 전에 완료 될 때까지 기다립니다.

대신 스레드를 만들고 시작하면서 목록에 추가 한 다음 스레드 목록을 반복하여 끝날 때까지 순서대로 결합하십시오.

using System.Collections.Generic; 
List<Thread> threads= new List<Thread>(); 
//Should create 10 files in a loop. 
for (var x = 0; x < 10; x++) 
{ 
    var y = x; 
    int threadId; 
    var myThread = new Thread(() => TestMethod("outpFile", y, out threadId)); 
    threads.Add(myThread); 
    myThread.Start(); 
    //myThread.Join(); 
    //TestMethod("outpFile", y, out threadId); 
} 
foreach (var thread in threads) thread.Join(); 
1

당신이 느린있어 그 이유는 모든 새 스레드를 시작하고 그것이 다른 방법은 간단하게 3 단계를 수행하지 않기 때문에 느린이어야하므로 완료 될 때까지 대기하고있는 것입니다.

이것을 시도해보십시오 (TPL로 인해 .Net 4.0이라고 가정). 내 컴퓨터에서 병렬로 실행하면 일관되게 100ms 빨라집니다.

[Test] 
public void Y() 
{ 
    var sw = Stopwatch.StartNew(); 
    Parallel.For(0, 10, n => TestMethod("parallel", n)); 

    sw.Stop(); 
    Console.WriteLine(sw.ElapsedMilliseconds); 

    sw.Restart(); 

    for (int i = 0; i < 10; i++) 
     TestMethod("forloop", i); 

    sw.Stop(); 
    Console.WriteLine(sw.ElapsedMilliseconds); 
} 


private static void TestMethod(string fileName, int hifi) 
{ 
    fileName = fileName + hifi; 
    var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); 
    var sw = new StreamWriter(fs, Encoding.UTF8); 
    for (int x = 0; x < 10000; x++) 
    { 
     sw.WriteLine(DateTime.Now.ToString()); 
    } 
    sw.Close(); 
} 
+1

+1 10과 100 개의 파일에서 테스트를했는데 100ms 차이가 있습니다. 100 파일에서 그것은 단지 2 %입니다. 병렬의 적절한 구현이지만 결국에는 하나의 물리적 디스크에 대해 여전히 경쟁합니다. – Paparazzi

+0

이 방법을 테스트 한 결과 현재 구현중인 것보다 약간 빠르다는 것을 알게되었습니다. 어떤 이유로 든 – abhi

1

귀하의 사례에서 관찰해야 할 주요 사항은 Amdahl's Law입니다. 귀하의 알고리즘은 다음 각 자원의 대략 동일하게 사용한다 :

  1. 프로세서 사용
  2. 이들의
  3. 드라이브 액세스

메모리 액세스가 드라이브 액세스가 훨씬 가장 느린에 의해 입니다 항목이 있으므로 속도 향상을 위해이 리소스에서 알고리즘을 병렬 처리해야합니다. 즉, 10 개의 다른 파일을 10 개의 다른 드라이브에 쓰면 프로그램을 병렬화하면 파일 내용의 계산을 병렬화하는 것보다 상당한 성능 향상을 볼 수 있습니다. 실제로 10 개의 다른 스레드에 파일을 작성하면 드라이브 액세스와 관련된 직렬화로 인해 실제로 프로그램의 전체 성능이 저하 될 수 있습니다.

둘 다 멀티 스레드 프로그래밍을 의미하지만 병렬화는 이 아니어야합니다.은 IO의 경우 비동기 프로그래밍과 동일하게 처리해야합니다. 파일 시스템의 사용을 병렬 처리하는 것을 권장하지는 않지만 파일을 읽고 쓰는 데 비동기 메서드를 사용하는 것이 거의 항상 유용합니다. 이 일련 통화보다 더 빨리 습관이라면 참으로 당신의 IO 당신이 그것에 대해 할 수있는 botleneck 아무것도가

for (int i = 0; i < 10; ++i) 
{ 
    new Action(() => { TestMethod("outpFile"); }).BeginInvoke(null,null); 
} 
Console.ReadLine(); 

:

0

같은 뭔가를하려고합니다.

+0

, 나는 10 개의 파일을 얻지 못합니다. 나는 4 파일을 얻고 모두 0 바이트 파일이다. 나는 예외가 던져지는 것을 보지 못한다. – abhi