2012-12-10 14 views
5

Tôi đang cố gắng viết một đoạn mã không đồng bộ thực sự đơn giản. Tôi có một phương pháp void mà không có bất kỳ tham số, đó là để được gọi từ một dịch vụ Windows. Tôi muốn khởi động nó không đồng bộ, để dịch vụ không phải chờ đợi cho đến khi phương pháp kết thúc.Tại sao phương thức không đồng bộ C# 4.0 này được gọi?

Tôi đã tạo một ứng dụng thử nghiệm rất đơn giản để đảm bảo rằng tôi đã thực hiện quyền mã hóa, nhưng phương pháp async không được gọi. Bất cứ ai có thể nhìn thấy những gì tôi đã làm sai? Tôi đang sử dụng .NET 4.0 bằng cách này, vì vậy tôi không thể sử dụng await (mà sẽ là một toàn bộ rất nhiều đơn giản!).

Dưới đây là toàn bộ mẫu thử nghiệm của tôi ...

using System; 
using System.Threading; 

namespace AsyncCallback { 
    internal class Program { 
    private static void Main(string[] args) { 
     Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - About to ask for stuff to be done"); 
     new Action(DoStuff).BeginInvoke(ar => StuffDone(), null); 
     Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Asked for stuff to be done"); 
    } 

    private static void StuffDone() { 
     Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Stuff done"); 
    } 

    private static void DoStuff() { 
     Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Starting to do stuff"); 
     Thread.Sleep(1000); 
     Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Ending doing stuff"); 
    } 
    } 
} 

Nhờ sự giúp đỡ bạn có thể cho.

+0

@ Martin: nơi là 'async'/'await' trong câu hỏi trên? – spender

+0

Tại sao không sử dụng .NET 4.5? – Rafael

+0

@spender Ông đã sử dụng "async" làm từ viết tắt mục đích chung cho "không đồng bộ" thay vì từ khóa C#. – Servy

Trả lời

6

Chương trình của bạn đang kết thúc trước khi phương thức async được triển khai trong ThreadPool. Giữ cho chương trình của bạn mở một chút. Có lẽ Console.ReadKey() ở cuối Main?

+0

Duh, thực sự rõ ràng! Cảm ơn vì điều đó. Tôi đã làm điều này trong một dự án thử nghiệm, do đó, không có bất cứ điều gì khác xảy ra sau cuộc gọi không đồng bộ. Quên rằng chuỗi sẽ kết thúc hoàn toàn. Cảm ơn. –

5

Mọi ứng dụng sẽ kết thúc ngay khi không có tiền cảnh chủ đề chưa hoàn thành thực thi. Nếu có bất kỳ chủ đề nền nào thì chúng sẽ không giữ cho quy trình "còn sống".

Vì bạn đang bắt đầu tác vụ không đồng bộ trong nền và không có gì giữ cho luồng tiền cảnh chạy, toàn bộ quá trình sẽ thoát.

Bạn cần phải chạy tác vụ không đồng bộ của mình trong một chủ đề thay thế (không thể thực hiện với BeginInvoke theo như tôi biết, bạn cần phải tạo một Thread mới rõ ràng) hoặc làm điều gì khác để chặn chủ đề chính cho đến khi nó kết thúc.

+0

Cảm ơn Servy, giống như spender, bạn đã trả lời câu hỏi :) –

1

You are not chờ đợi hoàn thành, vì vậy hãy thử một cái gì đó như thế này

Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - About to ask for stuff to be done"); 
var a = new Action(DoStuff); 
var iar = a.BeginInvoke(ar => StuffDone(), null); 
a.EndInvoke(iar); 
Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Asked for stuff to be done"); 
+0

mặc dù nếu bạn định đợi kết quả của tác vụ async, tại sao bắt đầu nó không đồng bộ ngay từ đầu ... – Servy

1

Để bắt đầu với, gọi lại của bạn không phải là đại biểu chính xác ... Nó phải là

public delegate void AsyncCallback(IAsyncResult ar); 

Và bạn là

private static void StuffDone() 

Chỉ cần thay đổi thành nội dung như sau:

private static void StuffDone(IAsyncResult ar){} 

Và sau đó trong cuộc gọi của bạn trở lại chắc chắn rằng hành động thực sự thực hiện bằng cách gọi

EndInvoke 

trên AsyncState

Như thế này:

private static void StuffDone(IAsyncResult ar) 
{ 
    Action r = ar.AsyncState as Action; 
    r.EndInvoke(ar); 

    Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Stuff done"); 
} 

Một thay đổi nữa bạn cần để thực hiện là, khi bạn khởi tạo Hành động trong hàm chính, chuyển chính hành động đó làm đối số 'đối tượng' của BeginInvoke phương pháp như thế này:

Action d = new Action(DoStuff); 
d.BeginInvoke(StuffDone, d); 

này phải giải quyết vấn đề của bạn :)