2017-06-26 24 views
5

Đọc qua số answers to this question nhắc tôi suy nghĩ về điều gì xảy ra ngoại lệ khi nhiệm vụ được chờ đợi ném. Tất cả "khách hàng" có quan sát ngoại lệ không? Tôi thừa nhận tôi có thể bối rối một vài điều ở đây; đó là lý do tôi yêu cầu làm rõ.Điều gì sẽ xảy ra khi nhiều luồng song song đang đợi cùng một cá thể Tác vụ mà sau đó sẽ ném?

Tôi sẽ trình bày một kịch bản cụ thể ... Giả sử tôi có một máy chủ có bộ sưu tập toàn cầu dài hạn Task trường hợp, được khách hàng bắt đầu. Sau khi bắt đầu một hoặc nhiều tác vụ, khách hàng có thể truy vấn tiến độ của họ và truy xuất kết quả khi họ có sẵn, cũng như bất kỳ lỗi nào có thể xảy ra.

Các tác vụ có thể thực hiện những điều cụ thể cho từng doanh nghiệp - thông thường, không có hai điều nào giống nhau. Tuy nhiên, nếu một trong các máy khách cố gắng bắt đầu nhiệm vụ tương tự như một công việc khác đã bắt đầu trước đó, máy chủ sẽ nhận ra điều này và "đính kèm" ứng dụng khách thứ hai vào tác vụ hiện có thay vì spooling lên một bản sao mới.

Bây giờ, mỗi lần bất kỳ khách hàng truy vấn tình trạng của công việc đó là quan tâm, nó làm điều gì đó dọc theo những dòng:

var timeout = Task.Delay(numberOfSecondsUntilClientsPatienceRunsOut); 
try 
{ 
    var result = await Task.WhenAny(timeout, task); 
    if (result == timeout) 
    { 
     // SNIP: No result is available yet. Just report the progress so far. 
    } 

    // SNIP: Report the result. 
} 
catch (Exception e) 
{ 
    // SNIP: Report the error. 
} 

Nói tóm lại, nó mang lại cho công việc một thời gian hợp lý để hoàn thành những gì nó làm đầu tiên , sau đó quay trở lại để báo cáo tiến độ đang diễn ra. Điều này có nghĩa là có một thời gian có khả năng đáng kể trong đó nhiều khách hàng có thể quan sát cùng một nhiệm vụ không thành công.

Câu hỏi của tôi là: nếu nhiệm vụ xảy ra để ném trong cửa sổ này, ngoại lệ có được tất cả các khách hàng quan sát và xử lý không?

+0

"Tác vụ trả về sẽ hoàn thành khi bất kỳ tác vụ nào được cung cấp đã hoàn thành. Tác vụ trả về sẽ luôn luôn kết thúc trong trạng thái' RanToCompletion' với 'Kết quả' được đặt thành công việc đầu tiên cần hoàn thành. nhiệm vụ hoàn thành đã kết thúc ở trạng thái Bị hủy hoặc Bị lỗi. " Nếu 'nhiệm vụ' lỗi, và được hoàn thành, và nhiều hơn một khách hàng đang chờ nó thông qua cấu trúc này, sau đó tất cả chúng sẽ thấy nhiệm vụ bị lỗi. Tất cả chúng sẽ có ngoại lệ nếu chúng cố gắng kiểm tra kết quả của 'task' (không phải' result'). Nó không phải là một thỏa thuận "đầu tiên đến, đầu tiên nhận được". –

+0

Để đơn giản hóa điều này hơn nữa: nếu bạn đang chờ đợi 'Task.Run (() => ném ngoại lệ mới (DateTime.Now.Ticks.ToString()))' nhiều lần trong một hàng (với một trình xử lý ngoại lệ), bạn sẽ nhận được một ngoại lệ mỗi lần, với cùng một dấu thời gian (để chứng minh nhiệm vụ không thực thi nhiều lần). Một nhiệm vụ bị lỗi có thể tạo ra nhiều ngoại lệ như bạn muốn. –

+2

Câu hỏi thú vị, nhưng đủ dễ dàng để kiểm tra bản thân. – spender

Trả lời

4

Task.WhenAny sẽ không tự ném. Mỗi the documentation:

Tác vụ được trả lại sẽ hoàn thành khi bất kỳ tác vụ nào được cung cấp hoàn thành . Tác vụ được trả lại sẽ luôn kết thúc ở trạng thái RanToCompletion với tập kết quả của nó là nhiệm vụ đầu tiên cần hoàn thành. Điều này đúng ngay cả khi công việc đầu tiên hoàn thành đã kết thúc ở trạng thái Canceled hoặc Faulted.

Bạn sẽ nhận lại hoặc timeout hoặc task.

Nếu kết quả là task và bạn đang chờ (hoặc nhận Task.Result) và task đã bị lỗi, thì điều đó sẽ bị ném. Không cần biết có bao nhiêu người gọi làm điều đó, hoặc khi họ làm điều đó - cố gắng để có được kết quả của một nhiệm vụ bị lỗi luôn luôn ném. Mã đơn giản để chứng minh điều này:

var t = Task.Run(() => throw new Exception(DateTime.Now.Ticks.ToString())); 
try { 
    await t; 
} catch (Exception e) { 
    Console.WriteLine(e.Message); 
} 
await Task.Delay(1000); 
try { 
    await t; 
} catch (Exception e) { 
    Console.WriteLine(e.Message); 
} 

Điều này sẽ in cùng một dấu thời gian, hai lần. Nhiệm vụ chỉ chạy một lần và chỉ có một kết quả, trong đó tạo ra một ngoại lệ mỗi khi bạn cố gắng để có được nó. Nếu bạn thích bạn có thể trộn lẫn trong các chủ đề khác nhau hoặc các cuộc gọi song song, điều này không thay đổi kết quả. Lưu ý rằng trong trường hợp hết thời gian chờ, vẫn có khả năng cơ bản của điều kiện chủng tộc: hai nhiệm vụ/chủ đề khác nhau, cả hai đang chờ nhiệm vụ tương tự, có thể nhận được kết quả khác nhau trên await Task.WhenAny(timeout, task), dựa trên nhiệm vụ nào họ quan sát hoàn thành đầu tiên. Nói cách khác, ngay cả khi await Task.WhenAny(timeout, task) == timeout, task vẫn có thể bị lỗi tại bất kỳ điểm nào giữa .WhenAny() quyết định việc này đã được thực hiện và kiểm soát cuối cùng sẽ quay lại với bạn.Điều này là để được mong đợi, và mã của bạn nên xử lý này (trên vòng tiếp theo chờ đợi, .WhenAny() sẽ trở lại ngay lập tức với nhiệm vụ bị lỗi).

+0

Để bất kỳ downvoters: xin vui lòng để lại một bình luận giải thích tại sao câu trả lời là sai, hoặc làm thế nào nó có thể được cải thiện. –

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