2015-03-12 13 views
7

Vì tôi phải thực hiện rất nhiều thao tác nhập/xuất tệp trong ứng dụng của mình, Tôi đã quyết định triển khai chúng không đồng bộ. Nhìn vào MSDN, không có đối tác không đồng bộ cho File.Create, File.Delete và File.Move. Như tôi đã học được, lý do là không tồn tại của một thực hiện Win32 không đồng bộ cho file xóa, tạo hoặc di chuyển, Vì vậy, tôi đã kết thúc với các giải pháp sau đây:Làm cách nào để triển khai tệp async.Delete/Create/Move?

public static Task DeleteAsync(string path) 
{ 
    Guard.FileExists(path); 

    return Task.Run(() => File.Delete(path)); 
} 

public static Task<FileStream> CreateAsync(string path) 
{ 
    Guard.IsNotNullOrWhitespace(path); 

    return Task.Run(() => File.Create(path)); 
} 

public static Task MoveAsync(string sourceFileName, string destFileName) 
{ 
    Guard.FileExists(sourceFileName); 
    Guard.IsNotNullOrWhitespace(destFileName); 

    return Task.Run(() => { File.Move(sourceFileName, destFileName); }); 
} 

Xét Paradigma "Don’t use Task.Run in Libraries", tôi tự hỏi nếu có một thực hiện tốt hơn hay tôi nên dự phòng mã đồng bộ?

Rất cám ơn trước!

Chỉnh sửa:


  • Cải thiện mã dựa trên Peter Duniho khuyến nghị
  • gia tăng liên kết đến bài đăng blog ban đầu được cung cấp bởi Sriram Sakthivel
+0

Ai nói "không sử dụng' Task.Run() 'trong thư viện"? Làm thế nào để bạn nghĩ rằng bạn có thể thực hiện các phương thức đồng bộ mà không sử dụng một trong hai điều đó, hoặc một cái gì đó tương đương với điều đó? Có bất cứ điều gì thực sự sai với việc thực hiện bạn có? –

+1

@PeterDuniho Đó là khuyến cáo của stepy cleary. Ông khuyên bạn không nên sử dụng 'Task.Run' khi triển khai thực hiện, nếu bạn cần bọc phương thức đồng bộ là hoạt động không đồng bộ, sau đó thực hiện nó trong mã máy khách mà bạn cần nó.Chỉnh sửa: Ngoài ra Stephen toub nói rằng không phơi bày wrapper không đồng bộ trên các phương thức đồng bộ. –

+0

Nhân tiện, việc triển khai của bạn dường như không hoàn hảo. Các phương thức nên tất cả chỉ trả về 'Task' (không cấu hình chờ đợi, và không có các phương thức là 'async'). 'CreateAsync()' có thể trả về Task.Run (() => File.Create (path)); '(nghĩa là nhiệm vụ awaitable trả lại sẽ tự trả về đối tượng' FileStream' ... không cần phải chờ đợi để làm điều đó và cũng không sử dụng tính năng ghi biến để hoàn thành nó). –

Trả lời

6

Nếu bạn phải làm điều này, Tôi sẽ viết các phương pháp như thế này (lưu ý: Tôi sẵn sàng đồng ý rằng đây chính xác là những gì Stephens Cleary và Toub đang thúc giục chúng tôi không làm):

public static Task DeleteAsync(string path) 
{ 
    Guard.FileExists(path); 

    return Task.Run(() => { File.Delete(path); }); 
} 

public static Task<FileStream> CreateAsync(string path) 
{ 
    Guard.IsNotNullOrWhitespace(path); 

    return Task.Run(() => File.Create(path)); 
} 

public static Task MoveAsync(string sourceFileName, string destFileName) 
{ 
    Guard.FileExists(sourceFileName); 
    Guard.IsNotNullOrWhitespace(destFileName); 

    return Task.Run(() => { File.Move(sourceFileName, destFileName); }); 
} 

Điều này làm sạch mã một chút và loại bỏ quá nhiều ngữ cảnh/chuyển đổi luồng.

Trong ngữ cảnh của một chương trình dựa trên GUI, có vẻ như tốt để sử dụng trình bao bọc như thế này. Tôi nghĩ rằng miễn là bạn không tạo một thư viện hoàn toàn mới với các API đồng bộ và không đồng bộ song song, như được mô tả trong các bài viết được nhắc đến, thì điều này không phải là khủng khiếp.

Nhưng đối với tôi, vấn đề lớn hơn là không có hoạt động nào trong số này có thể mất nhiều thời gian để biện minh cho việc này không đồng bộ ngay từ đầu. I E. lý do thông thường bạn chạy mọi thứ trong một Task từ một chuỗi giao diện người dùng là vì luồng giao diện người dùng của bạn không thể chờ đợi trong khi thao tác hoàn tất. Nhưng ở đây, đối với mỗi hoạt động này, hành động gửi hoạt động tới nhóm luồng, và sau đó chọn tiếp tục sau khi hoàn thành, có khả năng thêm nhiều chi phí hiệu năng vào chương trình của bạn như chính hoạt động đó.

Đó là vì rằng lý do tôi khuyên bạn không nên làm phiền với phiên bản không đồng bộ của các phương pháp. Chỉ cần gọi trực tiếp các phương thức Create(), Delete()Move() từ giao diện người dùng.

(Lưu ý: một ngoại lệ ở trên là nếu xử lý chia sẻ mạng hoặc các khối lượng khác nhau, trong đó Move() liên quan đến việc sao chép dữ liệu thực sự. Do đó, ngay cả ở đó, nó rất lớn "nó phụ thuộc". thường sẽ nhanh ngay cả trên mạng, họ có thể mất một lúc nếu thao tác thực sự bị lỗi. Bạn có thể thực sự có trường hợp sử dụng tốt để chạy các hoạt động không đồng bộ ở đó).

+0

Là một sidenote, sử dụng 'Guard.FileExists (sourceFileName)' đồng bộ có lẽ là sai. Nếu 'sourceFileName' nằm trên một máy tính khác, đó là chậm để trả lời, thì bạn đã quay trở lại điểm 0 :-) – xanatos

+0

@xanatos: vâng, tôi đồng ý với quan sát đó. Nếu không nhìn thấy việc thực hiện, bạn không thể biết chắc chắn, nhưng có vẻ như an toàn khi cho rằng nó chỉ ủy quyền cho 'File.Exists()' và ném một ngoại lệ nếu nó trả về 'false'. –

+0

@Peter Duniho: Trong WinRT, tất cả các thao tác tệp đều không đồng bộ, vì vậy tôi đã tự hỏi nếu điều này không có lợi cho các ứng dụng .NET phổ biến. Ok thực hiện không đồng bộ của File.Create là đáng ngờ, nhưng xóa và di chuyển có thể được chạy dài, ngay cả khi hoạt động thành công. Nó sẽ là một cách tiếp cận tốt trong quan điểm của bạn để chỉ cần thực hiện Move async và Create/Delete là đồng bộ? – Fabe

Các vấn đề liên quan