2012-12-12 35 views
5

Tôi đang tìm kiếm các từ khóa mới asyncawait trong C# và chỉ cố gắng để có được cảm nhận về chúng.FileStream WriteAsync và chờ đợi sự nhầm lẫn

Tôi đang xem MSDN FileStream.WriteAsync()example và tôi không chắc mình đã hiểu điều gì đó.

Ví dụ như sau:

using System; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.IO; 

namespace WpfApplication1 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private async void Button_Click(object sender, RoutedEventArgs e) 
     { 
      UnicodeEncoding uniencoding = new UnicodeEncoding(); 
      string filename = @"c:\Users\exampleuser\Documents\userinputlog.txt"; 

      byte[] result = uniencoding.GetBytes(UserInput.Text); 

      using (FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate)) 
      { 
       SourceStream.Seek(0, SeekOrigin.End); 
       await SourceStream.WriteAsync(result, 0, result.Length); 
      } 
     } 
    } 
} 

Những gì tôi không nhận được là vị trí của await. Có vẻ như bạn không thể lấy mục Task được trả về bởi WriteAsync() vì điều này luôn mang lại cho tôi một lỗi cú pháp. Vì vậy, cách duy nhất tôi có thể nhận được điều này để biên dịch là bằng cách rời khỏi await với cuộc gọi.

Nhưng nếu bạn làm điều này, không phải chờ cuộc gọi kết thúc? Điều này làm cho nó không phải là rất không đồng bộ ...

+0

Bạn có ý nghĩa gì khi "lấy" mục 'Tác vụ'? –

+0

@Jon Một cái gì đó như 'Task t = SourceStream.WriteAsync (kết quả, 0, result.Length);' và sau đó làm 'await t;' – Andrew

+2

Bạn chắc chắn có thể làm điều đó - điều gì khiến bạn nghĩ rằng bạn không thể? –

Trả lời

13

Tôi nghi ngờ vấn đề là với sự hiểu biết của bạn về những gì await.

Nhưng nếu bạn làm điều này, có phải không chờ cuộc gọi kết thúc? Điều này làm cho nó không phải là rất không đồng bộ ...

Khi bạn await gì đó, bạn "khối không đồng bộ" - chức năng không đồng bộ của bạn sẽ tiếp tục khi hoạt động không đồng bộ đã hoàn thành, nhưng các cuộc gọi ngay lập tức sẽ hoàn thành ngay lập tức.

Vì vậy, trong trường hợp của bạn, chuỗi giao diện người dùng bị hủy bỏ vì Button_Click trả về, nhưng khi thao tác ghi tệp hoàn tất, thực thi sẽ trả về (vẫn còn trong chuỗi giao diện người dùng) đến cuối biểu thức await ... bạn sẽ sau đó đóng FileStream và hoàn thành chức năng không đồng bộ.

Sẽ rõ ràng hơn những gì đang xảy ra nếu bạn đã làm điều gì khác sau biểu thức await (ví dụ: cập nhật giao diện người dùng). Nhưng có, nó thực sự không đồng bộ - nó chỉ cho phép bạn viết mã mà trông đồng bộ.

+0

Vì vậy, hãy nói rằng tôi đã thực hiện một số phương thức 'doWork()' sau 'await', phương thức này sẽ không được gọi cho đến khi viết xong? – Andrew

+3

@Andrew: Thật vậy.Nhưng trong khi chức năng không đồng bộ của bạn đang chờ đợi để hoàn thành, nó * sẽ không * được giữ thread UI. Nó giống như đặt một bánh pizza - bạn không thể * ăn * pizza cho đến khi nó được giao, nhưng bạn có thể làm những thứ khác thay vào đó :) –

+0

Tôi nghĩ điều đó có ý nghĩa. Cảm ơn! – Andrew

1

Sự chờ đợi không thực sự chặn trong khi chờ đợi. Điều gì xảy ra là trình biên dịch thực hiện một số công cụ phức tạp để thực hiện một sự tiếp nối được gọi là tất cả các mã sau khi chờ đợi và yêu cầu nhiệm vụ thực hiện việc tiếp tục đó khi nó được hoàn thành.

Về cơ bản các dòng cuối cùng của phương pháp Button_Click được dịch sang:

FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate); 
SourceStream.Seek(0, SeekOrigin.End); 
Task t = SourceStream.WriteAsync(result, 0, result.Length); 
t.ContinueWith(_ => SourceStream.Dispose()); 

Tất nhiên, điều này là đơn giản như thế này sẽ được thực hiện hiệu quả hơn nếu WriteAsync hoàn thành ngay lập tức, ví dụ.