2016-09-19 191 views
0

我不得不每次在不同參數的循環中調用約100次web服務方法。 Web服務只有同步方法。目前我正在一個控制檯應用程序中測試它,並且在同步進行數據時需要十分鐘的時間才能獲取數據!異步調用同步webservice方法

我想要的: 並行運行10個請求。完成後,執行接下來的十個呼叫。 這當然應該是異步的。

該功能將託管在IIS託管的wcf服務中。

概述: 客戶端調用使用參數一次WCF服務。 wcf服務方法應該異步調用另一個web服務一百次並將最終數據保存到Excel中。

我看過,那Task.Run在Web應用程序中使用時不是一個好主意。

那麼,如何在Web上下文中異步調用同步Web服務方法?

我使用的CRM Microsoft.Xrm.Sdk,版本= 7.0.0.0,文化=中性公鑰= 31bf3856ad364e35

var orders = _serviceProxy.RetrieveMultiple(new FetchExpression(strXmlFetch)); 

RetrieveMultiple得到其中查詢被定義並執行所請求的XML片段(strXmlFetch)。 方法駐留在這裏:

命名空間 Microsoft.Xrm.Sdk.Client
OrganizationServiceProxy

public EntityCollection RetrieveMultiple(QueryBase query); 

引擎蓋下的客戶端SDK確實主叫RetrieveMultiple時follwoing。

using (OrganizationServiceContextInitializer organizationServiceContextInitializer = new OrganizationServiceContextInitializer(this)) 
{ 
    entityCollection = base.ServiceChannel.Channel.RetrieveMultiple(query); 
    return entityCollection; 
} 

我還沒有實現任何東西,因爲我需要異步執行請求的起點。

+0

您可以使用Parallel.ForEach(https://msdn.microsoft .com/en-us/library/system.threading.tasks.parallel.foreach(v = vs.110).aspx) – Evk

+0

@Evk網絡IO的並行API,從來不是一個好主意,會浪費資源,它應該是Async-Await,在內部調用同步方法,或者可能是Async(如果可用) –

+0

但是OP說他的web服務只有同步方法。當然最好是利用異步IO,但問題狀態是不可能的。如果您將使用async \ await和Task.Run調用此同步方法 - 將不會改變任何內容。 – Evk

回答

1

這當然應該是異步的。

那麼,這將是理想的。但是,OrganizationServiceProxy does not have asynchronous methodsneither does IOrganizationService,所以直接使用ServiceChannel.Channel也無濟於事)。

因此,首先要做的就是要求微軟將異步API添加到該客戶端庫。

我看到,在Web應用程序中使用Task.Run並不是一個好主意。

通常情況是這樣;你想調用異步API。在這種情況下哪些不可用。

那麼,如何在Web上下文中異步調用同步Web服務方法?

這是不可能的。你的選擇是:

  1. 只是保持同步,一次一個。是的,這會花費更長的時間。
  2. 使它平行

與服務器端的並行處理的問題是,你現在使用N線程一個請求,我們可以真的很快把你的網絡服務器癱瘓。我不建議在生產代碼中使用這種方法,尤其是在通過Internet公開的情況下。

但是,如果你肯定不會有太多調用WCF服務,您可以並行執行。

,因爲你需要收集來自並行查詢結果,我推薦使用Parallel LINQAsParallel)指定WithDegreeOfParallelism(10),是這樣的:

IEnumerable<EntityCollection> GetAll(OrganizationServiceProxy proxy, IEnumerable<QueryBase> queries) 
{ 
    return queries.AsParallel().WithDegreeOfParallelism(10) 
     .Select(query => proxy.RetrieveMultiple(query)); 
} 
+0

目前我使用Task.Run來完成,但是使用ParallelForEach會更智能和方便。因此,例如,我需要獲取50000條記錄,當它進行同步時,50個呼叫每個返回1000,每個請求需要5秒鐘,總共250秒。有了並行性(WithDegree(50)),我預計它會在大約5到8秒內完成。但在我的情況下,在同步模式下運行需要90%的時間。我想在服務器端有一些阻塞...? – Legends

+0

在我的代碼中,我使用'WithDegreeOfParallelism(10)',20開始接收超時。 – Legends

+0

@傳說:服務器端很可能一次只限制一個請求。或者你遇到了其他一些瓶頸。在這種情況下可能會發生超時,因爲超時是從發出請求到結果到達的時間 - 如果服務器限制了您的請求,那麼您的一些請求將會人爲地延長時間。 –

1

的Web服務只同步方法

網絡默認服務產生有關BeginXX, EndXXAsynchronous方法,這是Asynchronous Programming Model一部分,但它們不是可以通過Async-Await消耗的一個,因爲他們不要返回Task

我想要什麼:運行10個請求並行。完成後,執行接下來的十個呼叫。這當然應該是異步的。

在真正Async電話,因爲沒有threads被調用和它適用於IO完成端口,因此你就可以開始有更多的電話,不僅僅是10。否則,一次安排10個異步請求的邏輯必須是自定義的,即使在使用Threadpool時也沒有開箱即用的機制,但並不保證並行請求的數量,但您可以設置Max Degree of Parallelism,以獲得更高並行API的限制。

概述:客戶端用params調用wcf服務一次。 wcf服務方法應該異步調用另一個web服務一百次並將最終數據保存到Excel中。

您希望所有的調用都是異步的,這樣就不會阻止Ui線程,無論是對於wcf服務還是web服務。

我讀過Task.Run在Web應用程序中使用時不是一個好主意。

真,因爲ThreadPool線程調用得到,它不會做任何事情後分派IO調用Web Service

那麼,如何異步調用同步Web服務方法,在網絡語境?

需要使用Sync方法的異步包裝,這是反模式,但沒有其他選擇。這將需要一個ThreadPool線,是這樣的:

public class AsyncWrapper 
{ 
    public async Task CallWcfAsync(<Parameters>) 
    { 
     SynchronizationContext _synchronizationContext = 
     SynchronizationContext.Current; 

    try 
    { 
     SynchronizationContext.SetSynchronizationContext(null); 
     await Task.Run(() => CallWcfMethod(<Parameters>)); 
    } 
    finally 
    {    
     SynchronizationContext.SetSynchronizationContext 
     (_synchronizationContext); 
    } 
    } 
} 

要點:

  1. CallWcfAsync是您需要的Async wrapper method

  2. 通知我已在同步上下文設置爲Null執行之前,然後重新設置,這是在Web應用程序中的行爲類似ConfigureAwait(false),否則會導致僵局,爲Sychronization Context等待時被阻塞。

+0

所以這最後一個包裝是使用Parallel.ForEach一樣,只是不太方便,因爲你需要實現批量(最多10個並行請求)。 – Evk

+0

@Evk在進一步思考的時候,這比使用普通的'Parallel.For'有更多的好處,除了控制'SynchronizationContext'外,爲了避免死鎖,它不會像Parallel那樣阻塞調用,所以將釋放調用/ Ui線程來處理其他任務,這是IO調用的本質。 –

+0

爲什麼贊成票,至少表現出最低限度的禮貌,以提供明確的理由 –