簡體   English   中英

.Net 4.5殺了我的TPL,現在怎么辦?

[英].Net 4.5 killed my TPL, now what?

圖表1:將Async(非async !)網絡調用包裝成Task一些代碼

public static Task<byte[]> GetAsync(IConnection connection, uint id)
{
    ReadDataJob jobRDO = new ReadDataJob();

    //No overload of FromAsync takes 4 extra parameters, so we have to wrap
    // Begin in a Func so that it looks like it takes no parameters except 
    // callback and state
    Func<AsyncCallback, object, IAsyncResult> wrapped = (callback, state) =>
                jobRDO.Begin(connection, 0, 0, id, callback, state);

    return Task<byte[]>.Factory.FromAsync(wrapped, ar =>
    {
        ErrorCode errorCode;
        UInt32 sError;
        UInt32 attribute;
        byte[] data = new byte[10];
        jobRDO.End(out errorCode, out sError, out attribute, out data);
        if(error != ErrorCode.NO_ERROR)  throw new Exception(error.ToString());
        return data;
    }, jobRDO);
}

安裝.Net 4.5(不指向VS,也不重新編譯)會阻止這種工作。 永遠不會調用回調。

任何想法可能導致這種情況,否則,我可以做些什么來嘗試進一步縮小問題的根本原因或解決問題?

重新編輯 :我和Stephen Toub交換了幾封電子郵件。 下面我嘗試將我原來的答案和他的答案合並成一個連貫的整體。

tl; dr來解決這個問題,強制CompleteSynchronously總是返回false( 告誡非lector )。


MSDN文檔.Net 4.5'破壞'更改

發布此問題后,我立即點擊了相關問題 ,最后選擇了“.NET Framework 4.5中的應用程序兼容性” ,其中有關於FromAsync

更改IAsyncResult實現必須同步完成,並且其CompletedSynchronously屬性必須返回true才能完成生成的任務。

影響 :如果IAsyncResult實現未完成同步執行但其CompletedSynchronously屬性返回True,則生成的任務將無法完成。

具有諷刺意味的是,(或令人憤怒的), CompletedSynchronously的頁面指出:

對實施者的說明IAsyncResult接口的大多數實現者都不會使用此屬性,並且應該返回false


Stephen Toub用以下內容澄清了這一點:

http://msdn.microsoft.com/en-us/library/hh367887%28v=VS.110%29.aspx#core上的表格,特別是“更改”的描述,是錯誤的(...) 。

.NET 4.5對FromAsync進行了更改,但並非所有IAsyncResult.CompletedSynchronously實現都必須返回true:這沒有任何意義。 變化是FromAsync實際上現在正在查看IAsyncResult's CompletedSynchronously (它在.NET 4中根本沒有看到它),因此它期望它是准確的。 因此,如果你有一個錯誤的IAsyncResult實現, FromAsync可能仍然在.NET 4中工作,而使用.NET 4.5,它不太可能使用錯誤的實現。

具體來說,如果IAsyncResult.CompletedSynchronously返回false 但是,如果它返回true ,則IAsyncResult實際上必須同步完成。 如果CompletedSynchronously返回trueIAsyncResult尚未完成,則您有一個需要修復的錯誤,並且從FromAsync返回的Task可能無法正確完成。

此更改是出於性能原因。


回到我的問題代碼

這是他非常有用的分析,我將其全部包含在內,因為它可能對IAsyncResult其他實現者有用:

問題似乎是你正在使用的庫有一個非常錯誤的IAsyncResult實現; 特別是,它正在錯誤地實現CompletedSynchronously 這是他們的實施:

 public bool CompletedSynchronously { get { return _isCompleted; } } public bool IsCompleted { get { return _isCompleted; } } 

它們的_isCompleted字段指示異步操作是否已完成,這很好,並且可以從IsCompleted返回它,因為該屬性用於指示操作是否已完成。 CompletedSynchronously不能只返回相同的字段: CompletedSynchronously需要返回操作是否同步完成,即它是否在調用BeginXx期間完成,並且它必須始終為給定的IAsyncResult實例返回相同的值。

考慮如何使用IAsyncResult.CompletedSynchronously的標准模式。 其目的是允許BeginXx的調用者繼續執行后續工作,而不是由於工作而進行回調。 這對於避免堆棧潛水尤為重要(想象一下所有實際同步完成的一系列異步操作:如果回調處理了所有工作,那么每個回調都會啟動下一個操作,其回調將啟動下一個操作,但是因為它們是同步完成的,它們的回調也將作為BeginXx方法的一部分同步調用,因此每次調用都會在堆棧上越來越深,直到它可能溢出):

 IAsyncResult ar = BeginXx(…, delegate(IAsyncResult iar) => { if (iar.CompletedSynchronously) return; … // do the completion work, like calling EndXx and using its result }, …); if (ar.CompletedSynchronously) { … // do the completion work, like calling EndXx and using its result } 

請注意,調用者和回調都使用相同的CompletedSynchronously屬性來確定哪些運行回調。 因此, CompletedSynchronously必須始終為此特定實例返回相同的值。 如果沒有,則很容易導致錯誤的行為。 例如,它們的實現具有CompletedSynchronously返回等效的IsCompleted 想象一下以下一系列事件:

  • BeginXx並啟動異步操作
  • BeginXx返回其調用者,該調用者檢查CompletedSynchronously ,這是錯誤的,因為操作尚未完成。
  • 現在操作完成並調用回調。 回調看到CompletedSynchronously為true,因此不執行任何后續工作,因為它假定調用者執行了此操作。
  • 現在沒有人跑或者會回調。

簡而言之,圖書館有一個錯誤。 如果您更改了CompletedSynchronously以返回true,則屏蔽了此問題,但您可能會導致另一個問題:如果調用者(在您的情況下, FromAsync )認為操作已經完成,它將立即調用EndXx方法,這將阻止,直到異步操作完成,因此您已將異步操作轉換為同步操作。 您是否嘗試過始終從CompletedSynchronously返回false而不是始終返回true?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM