2

アプリケーションにいくつかの問題があります。問題を再現するためのサンプル コードを次に示します。

サービス:

[ServiceContract]
    public interface IService1
    {
        [OperationContract]        
        string GetData(int value, int minDelaySeconds, int maxDelaySeconds);     
    }

    [ServiceBehavior(
    InstanceContextMode = InstanceContextMode.Single,
    ConcurrencyMode = ConcurrencyMode.Multiple)]    
    public class Service1 : IService1
    {
        /// <summary>
        /// Simulates an operation. Generates a random string, and sleeps for sometime to simulate a long running operation.
        /// </summary>
        /// <param name="value">length of string</param>
        /// <param name="min">minimum time delay. units: seconds</param>
        /// <param name="max">maximum time delay. units: seconds</param>
        /// <returns></returns>
        public string GetData(int value, int min, int max)
        {            
            var r = new Random();
            var bytes = new byte[value];
            r.NextBytes(bytes);
            var s = Convert.ToBase64String(bytes);
            Thread.Sleep(TimeSpan.FromSeconds(r.NextDouble() * (max - min) + min));
            return s;
        }
    }

サービス構成 (カスタム バインディングを使用):

<customBinding>
        <binding name="myHttpBinding">
          <reliableSession />
          <binaryMessageEncoding />
          <httpTransport  maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>
        </binding>
      </customBinding>

クライアント (サービスへの並列呼び出しを行います):

static void Main(string[] args)
        {
            using (var tw = Console.Out)
            {
                try
                {
                    ServicePointManager.DefaultConnectionLimit = 100;
                    int numberOfthreads, minDelay, maxDelay, minPayLoad, maxPayLoad, numberOfRequests;
                    ParseCmdArgs(args, out numberOfthreads, out minDelay, out maxDelay, out minPayLoad, out maxPayLoad, out numberOfRequests);
                    var interceptor = new Interceptor();                    
                    var r = new Random();
                    using (var svc = new ServiceReference1.Service1Client())
                    {
                        svc.Endpoint.EndpointBehaviors.Add(interceptor);
                        var tasks = new Task[numberOfthreads];
                        int threadId = 0;
                        for (int ctr = 0; ctr < numberOfthreads; ctr++)
                        {
                            tasks[ctr] = Task.Run(async () =>
                            {
                                int id = Interlocked.Increment(ref threadId);
                                var count = 0;
                                while (count < numberOfRequests)
                                {                                    
                                    Thread.CurrentThread.Name = id.ToString();                                
                                    await svc.GetDataAsync(r.Next(minPayLoad, maxPayLoad), minDelay, maxDelay);
                                    // you will be on a different thread now, than the thread which made the call
                                    Debug.Assert(string.IsNullOrEmpty(Thread.CurrentThread.Name)); // note
                                    count++;
                                }
                                tw.WriteLine("Thread {0} is exiting...", id);
                            });
                        }
                        Task.WaitAll(tasks);
                    }
                }
                catch (Exception e)
                {
                    LogException(e, tw);
                }
            }         
        }

クライアント構成:

<system.net>
    <connectionManagement>
      <add address="*" maxconnection="100"/>
    </connectionManagement>
  </system.net>
...
<customBinding>              
                <binding name="myHttpBinding">
                    <reliableSession />
                    <binaryMessageEncoding />
                    <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>
                </binding>
            </customBinding>

質問:

  1. シリアル リクエストの処理のみが表示されます。なんで?
  2. 多くの場合、メッセージがサーバーを離れてからクライアントに到達するまでの間に、大きな時間の遅延 (どの程度? 時には 60 秒以上) があります。その間に何が起こっているのですか?サービスとクライアントの両方が同じマシン上にあります。以下にクライアント時間を示し、簡潔にするためにサービス トレースを省略しました。
  3. スレッドが終了しようとしているときに、クライアントで例外が発生します。下記参照。なぜ、そしてこれを修正する方法は?
  4. 同時リクエストを行うために複数のスレッドを作成しないように、クライアント メソッドを修正する方法を教えてもらえますか? ソリューションは、lock ステートメントを使用しないという制約に従う必要があります。

// cmd ライン パラメータの説明: 5 つのリクエストが並行して行われ、遅延時間は 5 ~ 30 秒、メッセージ サイズは 100kb ~ 1MB で、各「スレッド」は終了する前に 5 回の呼び出しを行います。

c:\Users\me\Documents\Visual Studio 2012\Projects\ConsoleApplication8\Test
Client1\bin\Debug>run2 5 5 30 100000 1000000 5  
[2] 1 Sending request...Received Response 502,492.00 bytes in 18.8 sec  
[3] 2 Sending request...Received Response 313,662.00 bytes in 29.0 sec  
[4] 3 Sending request...Received Response 1,236,254.00 bytes in 27.5 sec  
[1] 4 Sending request...Received Response 1,250,170.00 bytes in 36.3 sec  
[5] 5 Sending request...Received Response 151,803.00 bytes in 54.8 sec  
[2] 6 Sending request...Received Response 625,859.00 bytes in 26.8 sec  
[4] 7 Sending request...Received Response 395,976.00 bytes in 47.6 sec  
[3] 8 Sending request...Received Response 945,664.00 bytes in 45.1 sec  
[1] 9 Sending request...Received Response 1,287,904.00 bytes in 73.5 sec  
[2] 10 Sending request...Received Response 1,312,428.00 bytes in 52.9 sec  
[5] 11 Sending request...Received Response 1,045,727.00 bytes in 103.3 sec  
[3] 12 Sending request...Received Response 190,310.00 bytes in 107.5 sec  
[4] 13 Sending request...  
[2] 14 Sending request...  
[1] 15 Sending request...  
[5] 16 Sending request...Received Response 1,323,274.00 bytes in 36.4 sec  
[3] 17 Sending request...Received Response 1,090,367.00 bytes in 13.4 sec  
[5] 18 Sending request...Received Response 458,598.00 bytes in 28.8 sec  
[3] 19 Sending request...Received Response 1,185,986.00 bytes in 28.3 sec  
[5] 20 Sending request...Received Response 731,178.00 bytes in 27.0 sec  
Thread 3 is exiting...  
Thread 5 is exiting...  



One or more errors occurred.  
   at System.Threading.Tasks.Task.WaitAll(Task[] tasks, Int32 millisecondsTimeout, CancellationToken cancellationToken)  
   at System.Threading.Tasks.Task.WaitAll(Task[] tasks, Int32 millisecondsTimeou
t)  
   at System.Threading.Tasks.Task.WaitAll(Task[] tasks)  
   at TestClient1.Program.Main(String[] args) in c:\Users\me\Documents\Vis  
ual Studio 2012\Projects\ConsoleApplication8\TestClient1\Program.cs:line 48  
The message could not be transferred within the allotted timeout of 00:01:00. Th  
ere was no space available in the reliable channel's transfer window. The time a  
llotted to this operation may have been a portion of a longer timeout.  
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)  
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncR  
esult result)  
   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[  
] outs, IAsyncResult result)  
   at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayC  
lass5`1.<CreateGenericTask>b__4(IAsyncResult asyncResult)  
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar,  
Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchron  
ization)  
--- End of stack trace from previous location where exception was thrown ---  
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)  
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot  
ification(Task task)  
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()  
   at TestClient1.Program.<>c__DisplayClass8.<<Main>b__0>d__a.MoveNext() in c:\U  
sers\me\Documents\Visual Studio 2012\Projects\ConsoleApplication8\TestClie  
nt1\Program.cs:line 40  
4

1 に答える 1

0
  1. (2) を参照してください。
  2. 私の最初の考えは、同時実行モードが複数に設定されていないことでした。でも、やっぱりこれは設定されていることがわかります。スロットルされている可能性があります。セッションはデフォルトで 10 に設定されていると思います。したがって、セッションのスロットルを設定していない場合、これが原因である可能性があります。ServiceThrottlingBehavior の maxConncurentSessions をより高い数値 (たとえば 20) に上げてみてください。

  3. アイドル タイムアウトの設定を超えているように見えるため、1 と 2 の解決策でこの問題が解決される可能性があります。もう少し心を開くことができれば、これはなくなると思います。

変更したいのは、クライアントの using (var svc = new ServiceReference1.Service1Client()) という構文です。詳細については、このドキュメントを参照してください。 http://msdn.microsoft.com/en-us/library/aa355056.aspx。WCF プロキシを使用する場合は、代わりに try/finally コンストラクトを使用する必要があります。

于 2013-03-16T23:30:17.760 に答える