2017-12-02 28 views
4

내가 비동기 실험하고 예상되지 않는다에서 콘솔 애플리케이션은 I가 10MB 인 임의의 콘텐츠 파일을 생성 한 후 위의 방법을 사용하여 복사 애플리케이션이 실행 된C#을 비동기/기다리고 진행보고는/기다리고 및 진행은 모든 복사 MB 이후 진행 상황을보고하는 비동기 파일 복사 방법을 쓴 그러므로보고 및 주문

private void MainProgram(string[] args) 
{ 
    Console.WriteLine("Create File..."); 
    var dir = Path.GetDirectoryName(typeof(MainClass).Assembly.Location); 
    var file = Path.Combine(dir, "file.txt"); 
    var dest = Path.Combine(dir, "fileCopy.txt"); 

    var rnd = new Random(); 
    const string chars = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); 
    var str = new string(Enumerable 
         .Range(0, 1024*1024*10) 
         .Select(i => letters[rnd.Next(chars.Length -1)]) 
         .ToArray()); 
    File.WriteAllText(file, str); 

    var source = new CancellationTokenSource(); 
    var token = source.Token; 

    var progress = new Progress<int>(); 
    progress.ProgressChanged += (sender, percent) => Console.WriteLine($"Progress: {percent}%"); 

    var task = CopyFileAsync(file, dest, token, progress); 
    Console.WriteLine("Start Copy..."); 
    Console.ReadLine(); 
} 

후 복사 프로세스가 정확한 순서로 실행되도록, 두 파일이 동일하다. 그러나 Console 출력은 다음과 같습니다.

Create File... 
Start Copy... 
Progress: 10% 
Progress: 30% 
Progress: 20% 
Progress: 60% 
Progress: 50% 
Progress: 70% 
Progress: 80% 
Progress: 40% 
Progress: 90% 
Progress: 100% 

응용 프로그램을 호출 할 때마다 순서가 다릅니다. 나는이 행동을 이해하지 못한다. 이벤트 처리기에 중단 점을 넣고 각 값을 확인하면 올바른 순서로 진행됩니다. 아무도 나에게 이것을 설명 할 수 있습니까?

나중에 진행률 표시 줄이있는 GUI 응용 프로그램에서이 기능을 사용하고 싶습니다. 항상 앞뒤로 건너 뛰고 싶지는 않습니다.

+0

IProgress에 대한 동기화 컨텍스트가 필요하며 CopyFileAsync() 메서드의 대기 작업에 ConfigureAwait (false)를 추가해야합니다. –

+0

진행률 는 동기화 컨텍스트를 사용하여 이벤트 처리기의 호출을 처리하므로 이벤트 핸들러가'. '호출과 같은 순서로 호출된다는 보장이 없습니다.Report'를 사용하면 시간과 동작에 따라 사용되는 특정 동기화 컨텍스트에 전적으로 의존합니다. –

+0

참고 사항 : FileStream에서 실제로 비동기 적으로 읽고 쓸 수있게하려면 FileOptions.Asynchronous 매개 변수를 사용하여 생성자를 사용하여 생성해야합니다. 그렇지 않으면 단지 스레드를 사용하여 비동기 IO 작업을 수행하게됩니다. – ckuri

답변

2

Progress<T>은 현재 SynchronizationContext을 캡처합니다. SynchronizationContext (콘솔 앱에서와 같이)이없는 경우 진행률 콜백은 스레드 풀 스레드에 대해 예약됩니다. 즉, 여러 콜백이 병렬로 실행될 수 있으며 물론 순서는 보장되지 않습니다. WPF에서

  1. : 윈폼에서 Dispatcher.BeginInvoke()

  2. : Control.BeginInvoke

내가 작업하고 있지 않다

UI 애플리케이션에서

는 동기화 컨텍스트에 게시하기로 거의 비슷하다 WinForms하지만 WPF에서는 동일한 우선 순위를 가진 BeginInvoke이 여러 개 있습니다 (이 경우 동일한 우선 순위를가집니다). guaranteed는 호출 된 순서대로 실행합니다 :

여러 BeginInvoke 호출은 동일한 DispatcherPriority에서 그들이 호출이 만들어진 순서대로 실행됩니다 만들어진다.

나는 위해 우리의 실행 이유 윈폼 Control.BeginInvoke에 표시되지 않습니다,하지만 난 WPF를 위해 이상을 제공하는 것처럼 증거 잘 모르는 것 같아요. 그래서 나는 WPF와 WinForms 모두에서 순서대로 실행되도록 진행 콜백을 신뢰할 수 있다고 생각합니다 (컨텍스트를 캡처 할 수 있도록 UI 스레드에 Progress<T> 인스턴스 자체를 만든 경우).

사이트 참고 : 그 await의 후 UI 애플리케이션에서 UI 스레드에 모든 시간을 반환 방지하기 위해 ReadAsyncWriteAsync 통화를 ConfigureAwait(false)를 추가해야합니다.

+0

집에서 WPF를 테스트 할 Windows PC가 없기 때문에 나는 사무실에있을 때 월요일에 테스트 할 것입니다. :) – Buchter