Task.StartNew() 多次调用只返回一次

Task.StartNew() called multiple times only returning once

我使用了以下代码:

var tuple = Tuple.Create("xxx.xx.xx.xxx", 6102, "109", "Metrix1", 1);
var tuple1 = Tuple.Create("xxx.xx.xx.xxx", 6102, "110", "Metrix2", 1);
var tuple2 = Tuple.Create("xxx.xx.xx.xxx", 6102, "111", "Metrix3", 1);
var tuple3 = Tuple.Create("xxx.xx.xx.xxx", 6103, "106", "Metrix4", 2);

gateways.Add(tuple);
gateways.Add(tuple1);
gateways.Add(tuple2);
gateways.Add(tuple3);

foreach (var gatewayId in gateways)
{
    Task.Factory.StartNew(
        () => GetJobs(
            gatewayId.Item1,
            gatewayId.Item2,
            gatewayId.Item3,
            gatewayId.Item4,
            gatewayId.Item5));
}

然后调用 GetJobs,后者调用 CallGateway,如果需要 ProcessMessageNew

private string GetJobs(string Url , int portNumber, string Engineer , string mEngineer , int GatewayId)
{
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway Start: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + Engineer);
    string gatewayResult = CallGateway(Engineer, Url, portNumber);
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway End: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + Engineer);
    if (gatewayResult != null)
    {
        ConfigLogger.Instance.LogInfo("info", "Processing Request Message: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + Engineer);
        ProcessMessageNew(gatewayResult, Engineer, Url, portNumber , MEngineer ,PGatewayId);
    }
    return gatewayResult;
}

CallGateway:

public string CallGateway(string gatewayUrl, int portNumber , string engineer)
{
     string result = null;
     int streamBufferSize = 1000;

     IPHostEntry ipHostInfo = Dns.Resolve(gatewayUrl.ToString());
     IPAddress ipAddress = ipHostInfo.AddressList[0];
     IPEndPoint remoteEP = new IPEndPoint(ipAddress, portNumber);

     // Create a TCP/IP  socket.
     Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     clientSocket.Connect(ipAddress, portNumber);

     // Set these on app param
     clientSocket.ReceiveTimeout = 300000;
     clientSocket.SendTimeout = 60000;
     // build message string to send to gateway
     string message = BuildMessageGetJobsFromGateway(engineer, SendTypeIn);

     // Create a NetworkStream that owns clientSocket and 
     // then create a BufferedStream on top of the NetworkStream. 
     // Both streams are disposed when execution exits the 
     // using statement. 
     using (var netStream = new NetworkStream(clientSocket, true),
            var bufStream = new BufferedStream(netStream, streamBufferSize))
     {
          // Check whether the underlying stream supports seeking.
          Console.WriteLine("NetworkStream {0} seeking.\n", bufStream.CanSeek ? "supports" : "does not support");

          //variable used to only close once
          bool doClose = true;

          // Send and receive data. 
          if (bufStream.CanWrite)
          {
              try
              {
                  SendData(netStream, bufStream, SendTypeIn, message);
              }
              catch (Exception exSend)
              {
                  Console.WriteLine(exSend.Message.ToString());
              }
           }
           if (bufStream.CanRead)
           {
                try
                {
                     result = ReceiveData(netStream, bufStream, clientSocket);
                }
                catch (Exception exRecieve)
                {
                    //
                }
                finally
                {
                    Console.WriteLine("Closing Stream");
                    doClose = false;
                    bufStream.Close();
                    clientSocket.Close();
                }
            }

            // When bufStream is closed, netStream is in turn 
            // closed, which in turn shuts down the connection 
            // and closes clientSocket.
            Console.WriteLine("\nShutting down the connection.");

            // only close if no exception is raised
            if (doClose)
            {
                bufStream.Close();
                clientSocket.Close();
            }
        }
        return result;
    }
}

但是,我在日志文件中得到了这个调用网关方法的 4 个调用,工程师 106 只有一个 return,对网关的调用创建了一个套接字客户端,然后接收数据,但它只是发生了对于 4 个调用中的一个:

[MobileGateway.exe] - [Info] - [25/09/2015 16:47:19] - Calling Gateway Start: 16:47:19.6574 for engineer: 109
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:19] - Processing Call Mobile Gateway: 16:47:19.6624
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:20] - Calling Gateway Start: 16:47:20.6685 for engineer: 110
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:20] - Processing Call Mobile Gateway: 16:47:20.6875
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:21] - Calling Gateway Start: 16:47:21.6696 for engineer: 111
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:21] - Processing Call Mobile Gateway: 16:47:21.6716
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:22] - Calling Gateway Start: 16:47:22.6686 for engineer: 106
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:22] - Processing Call Mobile Gateway: 16:47:22.6706
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Processing Call Mobile Ended: 16:47:23.0476
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Calling Gateway End: 16:47:23.0486 for engineer: 106
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Processing Request Message: 16:47:23.0486 for engineer: 106
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Message Recieved From Gateway: 16:47:23.0496

调用应该以并行或异步方式处理,因为需要同时调用此方法超过 1000 次,而且它们是很长的 运行 进程,所以我需要一次处理多个。

知道为什么我得到 1 个响应而不是 4 个吗?

由于您在代码中对地址进行了 xxx 化,我不能肯定地说,但这可能会发生,因为前三个网关的端口号 6102 相同。因此,您正在为同一地址并行关闭和打开流 3 次,这会抛出异常,但稍后会被静默捕获。

此外,您可以通过如下方式单独传递网关对象来提高代码的可读性和可维护性:

foreach (var gatewayId in gateways) 
{
    Task.Factory.StartNew(() => GetJobs(gatewayId)); 
}

并将您的 GetJobs 方法也修改为:

private string GetJobs(Gateway gateway)
{
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway Start: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + gateway.Engineer);
    string gatewayResult = CallGateway(gateway);
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway End: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + gateway.Engineer);
    if (gatewayResult != null)
    {
        ConfigLogger.Instance.LogInfo("info", "Processing Request Message: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + gateway.Engineer);
        ProcessMessageNew(gatewayResult, gateway);
    }
    return gatewayResult;
}

另外,继续往下,也更改 ProcessMessageNewCallGateway,以匹配上面代码中的新定义。