2009-07-21 49 views
51

Tôi có phương pháp đơn giản trong ứng dụng C#, nó chọn tệp từ máy chủ FTP và phân tích cú pháp và lưu trữ dữ liệu trong DB. Tôi muốn nó không đồng bộ, để người dùng thực hiện các hoạt động khác trên ứng dụng, khi phân tích cú pháp được thực hiện, anh ta phải nhận được thông báo cho biết "Phân tích cú pháp được thực hiện".Cách tạo phương thức không đồng bộ

Tôi biết nó có thể đạt được thông qua cuộc gọi phương thức không đồng bộ nhưng Tôi không biết làm thế nào để làm điều đó ai có thể giúp tôi xin vui lòng ??

+0

Chỉ cần muốn đề cập - có 2 cách để thực hiện cuộc gọi không đồng bộ: với chủ đề và với các đại biểu. –

+0

Rất đơn giản. Bạn tạo một đại biểu. Gán chức năng của bạn cho nó và sau đó bạn thực hiện cuộc gọi không đồng bộ. [Điều này] (http://msdn.microsoft.com/en-us/magazine/cc301332.aspx) bài viết mô tả nó rất tốt (nó cũng dạy cho bạn những gì là một đại biểu). –

+1

Liên kết không hoạt động đối với tôi ?? –

Trả lời

4

Dưới đây là hai liên kết về luồng trong C#

Tôi muốn bắt đầu đọc về BackgroundWorker class

+0

Cảm ơn bạn đã phản hồi, có thể thực hiện nó mà không có chủ đề, có thể với đại biểu không? –

+0

Bạn có thể sử dụng BeginInvoke(), nhưng điều đó cũng gọi ra một luồng khác. Thực sự, có một cái nhìn tại BackgroundWorker - nó rất dễ sử dụng và cung cấp một thông báo khi công việc được thực hiện. – tanascius

74

Bạn cần phải sử dụng các đại biểu và các BeginInvoke phương pháp mà chúng chứa để chạy một phương thức khác không đồng bộ. Một kết thúc của phương thức được điều hành bởi đại biểu, bạn có thể thông báo cho người dùng. Ví dụ:

class MyClass 
{ 
    private delegate void SomeFunctionDelegate(int param1, bool param2); 
    private SomeFunctionDelegate sfd; 

    public MyClass() 
    { 
     sfd = new SomeFunctionDelegate(this.SomeFunction); 
    } 

    private void SomeFunction(int param1, bool param2) 
    { 
     // Do stuff 

     // Notify user 
    } 

    public void GetData() 
    { 
     // Do stuff 

     sfd.BeginInvoke(34, true, null, null); 
    } 
} 

đọc tại http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

+18

Lưu ý rằng thay vì khai báo và sử dụng 'SomeFunctionDelegate' bạn chỉ có thể sử dụng' Action 'và tương tự như một' Func 'cho các phương thức không bị vô hiệu. –

+2

Hành động mới (MethodName) .BeginInvoke (1, "văn bản", null, null); –

+0

** đây là các đại biểu không đồng bộ và không đồng bộ phương pháp **. Phương pháp không đồng bộ tuân theo một giao thức tương tự bên ngoài, nhưng chúng tồn tại để giải quyết nhiều hơn vấn đề khó khăn hơn –

1

ThreadPool.QueueUserWorkItem là cách nhanh nhất để có được một quá trình đang chạy trên một chủ đề khác nhau.

Hãy lưu ý rằng các đối tượng giao diện người dùng có "ái lực chuỗi" và không thể truy cập được từ bất kỳ chuỗi nào khác ngoài chủ đề đã tạo chúng.

Vì vậy, ngoài việc kiểm tra ThreadPool (hoặc sử dụng mô hình lập trình không đồng bộ thông qua các đại biểu), bạn cần kiểm tra Dispatchers (wpf) hoặc InvokeRequired (winforms).

+0

Nếu bất kỳ ai không cần truy cập vào các phần tử giao diện người dùng được tạo trên một luồng khác (ngoại lệ chéo), hãy xem bài đăng tuyệt vời này: http://stackoverflow.com/questions/142003/cross-thread-operation-not-valid-control-accessed -from-a-thread-other-than-the-t –

6

Bất cứ khi nào bạn đang làm điều gì đó không đồng bộ, bạn đang sử dụng một chuỗi riêng biệt, một chuỗi mới hoặc một chuỗi được lấy từ nhóm chủ đề. Điều này có nghĩa rằng bất cứ điều gì bạn làm không đồng bộ phải rất cẩn thận về tương tác với các chủ đề khác.

Một cách để làm điều đó là đặt mã cho chuỗi không đồng bộ (gọi là chuỗi "A") cùng với tất cả dữ liệu của nó vào một lớp khác (gọi là lớp "A"). Đảm bảo rằng chuỗi "A" chỉ truy cập dữ liệu trong lớp "A". Nếu chủ đề "A" chỉ chạm vào lớp "A", và không có thread khác chạm vào lớp "A" của dữ liệu, sau đó có một ít vấn đề:

public class MainClass 
{ 
    private sealed class AsyncClass 
    { 
     private int _counter; 
     private readonly int _maxCount; 

     public AsyncClass(int maxCount) { _maxCount = maxCount; } 

     public void Run() 
     { 
      while (_counter++ < _maxCount) { Thread.Sleep(1); } 
      CompletionTime = DateTime.Now; 
     } 

     public DateTime CompletionTime { get; private set; } 
    } 

    private AsyncClass _asyncInstance; 
    public void StartAsync() 
    { 
     var asyncDoneTime = DateTime.MinValue; 
     _asyncInstance = new AsyncClass(10); 
     Action asyncAction = _asyncInstance.Run; 
     asyncAction.BeginInvoke(
      ar => 
       { 
        asyncAction.EndInvoke(ar); 
        asyncDoneTime = _asyncInstance.CompletionTime; 
       }, null); 
     Console.WriteLine("Async task ended at {0}", asyncDoneTime); 
    } 
} 

Chú ý rằng phần duy nhất của AsyncClass đó là chạm từ bên ngoài là giao diện công cộng của nó và phần duy nhất của dữ liệu là CompletionTime. Lưu ý rằng đây là chỉ được chạm sau khi tác vụ không đồng bộ hoàn tất. Điều này có nghĩa rằng không có gì khác có thể can thiệp vào các nhiệm vụ bên trong hoạt động, và nó không thể can thiệp với bất cứ điều gì khác.

+2

Chuỗi "Tác vụ không đồng bộ đã kết thúc lúc {0}" không được in sau khi tác vụ không đồng bộ kết thúc ... – Jacob

+2

Plz sửa câu lệnh của bạn "Bất kỳ lúc nào bạn đang thực hiện một cái gì đó không đồng bộ, bạn đang sử dụng một chủ đề riêng biệt ". Điều đó là sai. Kiểm tra [Không đồng bộ trong C# 5.0 phần Bốn: Nó không phải là phép thuật] (http://blogs.msdn.com/b/ericlippert/archive/2010/11/04/asynchrony-in-c-5-0-part-four- it-s-not-magic.aspx) –

+0

Nó luôn luôn là một chuỗi _separate_, một cách hợp lý, ngay cả khi, về thể chất, cùng một luồng có thể được sử dụng lại. –

0

Cuối cùng, bạn sẽ phải sử dụng một số loại luồng. Cách nó hoạt động cơ bản là bạn bắt đầu một hàm với một luồng mới và nó sẽ chạy cho đến khi kết thúc hàm.

Nếu bạn đang sử dụng Biểu mẫu Windows thì một trình bao bọc đẹp mà họ có cho điều này gọi là Công nhân nền. Nó cho phép bạn làm việc trong nền với việc khóa lên biểu mẫu giao diện người dùng và thậm chí cung cấp một cách để giao tiếp với các biểu mẫu và cung cấp các sự kiện cập nhật tiến trình.

Background Worker

4

Trong Asp.Net tôi sử dụng rất nhiều phương pháp tĩnh cho công việc phải làm. Nếu nó chỉ đơn giản là một công việc mà tôi cần không có phản ứng hoặc trạng thái, tôi làm một cái gì đó đơn giản như dưới đây. Như bạn có thể thấy, tôi có thể chọn gọi ResizeImages hoặc ResizeImagesAsync tùy thuộc vào việc tôi muốn đợi nó hoàn thành hay không

Giải thích mã: Tôi sử dụng http://imageresizing.net/ để đổi kích thước/cắt hình ảnh và phương pháp SaveBlobPng là lưu trữ hình ảnh sang Azure (đám mây) nhưng vì điều đó không liên quan đến bản demo này nên tôi không bao gồm mã đó. Đó là một ví dụ tốt về nhiệm vụ tốn thời gian mặc dù

private delegate void ResizeImagesDelegate(string tempuri, Dictionary<string, string> versions); 
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions) 
{ 
    ResizeImagesDelegate worker = new ResizeImagesDelegate(ResizeImages); 
    worker.BeginInvoke(tempuri, versions, deletetemp, null, null); 
} 
private static void ResizeImages(string tempuri, Dictionary<string, string> versions) 
{ 
    //the job, whatever it might be 
    foreach (var item in versions) 
    { 
     var image = ImageBuilder.Current.Build(tempuri, new ResizeSettings(item.Value)); 
     SaveBlobPng(image, item.Key); 
     image.Dispose(); 
    } 
} 

Hoặc sẽ cho luồng, do đó bạn không cần phải bận tâm với đại biểu

private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions) 
{ 
    Thread t = new Thread (() => ResizeImages(tempuri, versions, null, null)); 
    t.Start(); 
} 
18

thử phương pháp này

public static void RunAsynchronously(Action method, Action callback) { 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
     try { 
      method(); 
     } 
     catch (ThreadAbortException) { /* dont report on this */ } 
     catch (Exception ex) { 
     } 
     // note: this will not be called if the thread is aborted 
     if (callback!= null) callback(); 
    }); 
} 

Cách sử dụng:

RunAsynchronously(() => { picks file from FTP server and parses it}, 
     () => { Console.WriteLine("Parsing is done"); }); 
Các vấn đề liên quan