2012-12-17 20 views
1

我想了解wcf中的併發性,並從here下載了示例代碼,並對測試雙向調用進行了一些更改。令我驚訝的是我看不到雙向調用的併發效果(儘管我可以看到單向調用的併發效果)。 WCF併發模型的工作方式是什麼? (或) 我在做一些可怕的錯誤嗎?什麼是在wcf服務中實現併發的正確方法?

這是服務代碼。

[ServiceContract] 
public interface IHelloWorldService 
{ 
    [OperationContract(IsOneWay=true)] 
    void Call(string ClientName); 

    [OperationContract] 
    string GetData(int value); 

    [OperationContract] 
    CompositeType GetDataUsingDataContract(CompositeType composite); 
} 
[DataContract] 
public class CompositeType 
{ 
    bool boolValue = true; 
    string stringValue = "Hello "; 

    [DataMember] 
    public bool BoolValue 
    { 
     get { return boolValue; } 
     set { boolValue = value; } 
    } 

    [DataMember] 
    public string StringValue 
    { 
     get { return stringValue; } 
     set { stringValue = value; } 
    } 
} 
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class HelloWorldService : IHelloWorldService 
{ 
    public static int counter; 

    public HelloWorldService() 
    { 
     counter++; 
    } 

    public void Call(string ClientName) 
    {    
     Console.WriteLine("Instance:" + counter.ToString() + " Thread:" + Thread.CurrentThread.ManagedThreadId.ToString() + " Time:" + DateTime.Now.ToString() + "\n\n"); 
     Thread.Sleep(5000); 
    } 

    public string GetData(int value) 
    { 
     Console.WriteLine("Instance:" + counter.ToString() + " Thread:" + Thread.CurrentThread.ManagedThreadId.ToString() + " Time:" + DateTime.Now.ToString() + "\n\n"); 
     Thread.Sleep(5000); 
     return value.ToString(); 
    } 

    public CompositeType GetDataUsingDataContract(CompositeType composite) 
    { 
     Console.WriteLine("Instance:" + counter.ToString() + " Thread:" + Thread.CurrentThread.ManagedThreadId.ToString() + " Time:" + DateTime.Now.ToString() + "\n\n"); 
     Thread.Sleep(5000); 
     return composite; 
    } 
} 

這是服務託管代碼。

class Program 
{ 
    static void Main(string[] args) 
    { 
     //Create a URI to serve as the base address 

     //Uri httpUrl = new Uri("net.tcp://localhost:8001/HelloWorld"); 
     Uri httpUrl = new Uri("http://localhost:8010/MyService/HelloWorld"); 

     //Create ServiceHost 
     ServiceHost host 
     = new ServiceHost(typeof(ClassLibrary1.HelloWorldService), httpUrl); 

     //Add a service endpoint 
     host.AddServiceEndpoint(typeof(ClassLibrary1.IHelloWorldService) 
     , new WSHttpBinding(), ""); 

     //Enable metadata exchange 
     ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); 
     smb.HttpGetEnabled = true; 
     host.Description.Behaviors.Add(smb); 

     ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior(); 
     stb.MaxConcurrentCalls = 100; 
     stb.MaxConcurrentInstances = 100; 
     stb.MaxConcurrentSessions = 100; 
     host.Description.Behaviors.Add(stb); 


     //Start the Service 
     host.Open(); 

     Console.WriteLine("Service is host at " + DateTime.Now.ToString()); 
     Console.WriteLine("Host is running... Press <Enter> key to stop"); 
     Console.ReadLine(); 

    } 
} 

這是客戶端代碼。

class Program 
{ 
    static int m_NumberOfWorkers = 10; 
    static readonly object m_Locker = new object(); 
    static bool flag_GO = false; 
    static Stopwatch m_OverAllStopwatch = new Stopwatch(); 
    static ConcurrentBag<Stopwatch> m_bagIndividualStopwatch = new ConcurrentBag<Stopwatch>(); 
    static int m_CompletedWorkers = 0; 
    static ServiceReference1.HelloWorldServiceClient m_objProxy; 
    static int m_KindOfMethod; 
    static void Main(string[] args) 
    { 
     while(true) 
     { 
      try 
      { 
       flag_GO = false; 

       Console.WriteLine("Enter number of concurrent clients:"); 
       m_NumberOfWorkers = Int32.Parse(Console.ReadLine()); 

       Console.WriteLine("Kind of method (1: One way, 2: Two way 3: Two way using data contract):"); 
       m_KindOfMethod = Int32.Parse(Console.ReadLine()); 

       // Create Workers 
       List<Thread> lstThreads = new List<Thread>(); 
       for (int i = 0; i < m_NumberOfWorkers; ++i) 
       { 
        lstThreads.Add(new Thread(WaitOnPulse)); 
       } 

       // Start Workers 
       for (int i = 0; i < lstThreads.Count; ++i) 
       { 
        lstThreads[i].Start(); 
       } 

       m_objProxy = new ServiceReference1.HelloWorldServiceClient(); 

       m_OverAllStopwatch.Restart(); 

       // Signal all workers 
       lock (m_Locker) 
       { 
        flag_GO = true; 
        Monitor.PulseAll(m_Locker); 
       } 

       // Wait all workers to finish 
       for (int i = 0; i < lstThreads.Count; ++i) 
       { 
        lstThreads[i].Join(); 
       } 

       m_objProxy.Close(); 
       m_objProxy = null; 
      } 
      catch 
      { 
       return; 
      } 
     }    
    } 

    private static void WaitOnPulse() 
    { 
     lock (m_Locker) 
     { 
      while (!flag_GO) Monitor.Wait(m_Locker); 
     } 
     TestWhatEverYouWant(); 
     IamDone(); 
    } 

    private static void TestWhatEverYouWant() 
    { 
     Stopwatch stopWatch = Stopwatch.StartNew(); 
     //Thread.Sleep(1000); 
     switch (m_KindOfMethod) 
     { 
      case 1: 
       m_objProxy.Call(m_NumberOfWorkers.ToString() + "Client Calls"); 
       break; 
      case 2: 
       m_objProxy.GetData(m_NumberOfWorkers); 
       break; 
      case 3: 
       ServiceReference1.CompositeType objData = new ServiceReference1.CompositeType(); 
       m_objProxy.GetDataUsingDataContract(objData); 
       break; 
     } 
     stopWatch.Stop(); 
     m_bagIndividualStopwatch.Add(stopWatch); 
    } 

    private static void IamDone() 
    { 
     Interlocked.Increment(ref m_CompletedWorkers); 
     // Summarize results if all workers are done 
     if (Interlocked.CompareExchange(ref m_CompletedWorkers, 0, m_NumberOfWorkers) == m_NumberOfWorkers) 
     { 
      m_OverAllStopwatch.Stop(); 
      Console.WriteLine("OverAll Elapsed Time: {0}", m_OverAllStopwatch.ElapsedMilliseconds); 
      Stopwatch stopWatch; 
      while (m_bagIndividualStopwatch.TryTake(out stopWatch)) 
      //foreach (Stopwatch stopWatch in m_bagIndividualStopwatch) 
      { 
       Console.WriteLine("Individual Elapsed Time: {0}", stopWatch.ElapsedMilliseconds); 
      } 
     } 
    } 
} 

這是Cleint跟蹤:

Enter number of concurrent clients: 
    8 
    Kind of method (1: One way, 2: Two way 3: Two way using data contract): 
    2 
    OverAll Elapsed Time: 42022 
    Individual Elapsed Time: 42021 
    Individual Elapsed Time: 37013 
    Individual Elapsed Time: 32008 
    Individual Elapsed Time: 26987 
    Individual Elapsed Time: 21981 
    Individual Elapsed Time: 16980 
    Individual Elapsed Time: 11968 
    Individual Elapsed Time: 6985 

這是服務器跟蹤:

Instance:1 Thread:6 Time:12/17/2012 8:09:29 PM 


    Instance:1 Thread:5 Time:12/17/2012 8:09:34 PM 


    Instance:1 Thread:7 Time:12/17/2012 8:09:39 PM 


    Instance:1 Thread:7 Time:12/17/2012 8:09:44 PM 


    Instance:1 Thread:5 Time:12/17/2012 8:09:49 PM 


    Instance:1 Thread:7 Time:12/17/2012 8:09:54 PM 


    Instance:1 Thread:5 Time:12/17/2012 8:09:59 PM 


    Instance:1 Thread:7 Time:12/17/2012 8:10:04 PM 

對於這些結果可以清楚地看到,該請求被依次處理。理想情況下,我期待所有8個併發請求都會在5秒內完成。但大約需要42秒才能完成。

回答

0

我的代碼中的問題是使用代理的方式。我爲所有併發客戶創建了一個代理,並且所有對該服務的調用都是通過此代理完成的。所以,所有這些電話都在頻道中排隊等候。 爲每個客戶端創建一個代理,應該模擬wcf負載測試的方式,解決了這個問題。

-1

我仍然認爲問題在於設置;代理和源自每個代理的線程數量,鏈接很好地解釋了它。

也看看下面的鏈接;可能是測試客戶端可能會有問題。 Seeking WCF Duplex "TwoWay" Subscribe+Callback Example

+0

僅供鏈接的答案沒有幫助。如果你確實提供了一個鏈接,它應該支持你的答案。如果鏈接失效,鏈接唯一的答案也完全失去意義。 –

相關問題