【问题标题】:Sending data over sockets is slower with concurrent threads?并发线程通过套接字发送数据更慢?
【发布时间】:2017-05-05 13:44:05
【问题描述】:

下面我有一个应用程序,我尝试使用 C# 套接字以最快的方式发送尽可能多的数据。数据开始 10 秒后,我停止数据发送并等待控制台键,同时向控制台写入发送了多少请求。

将线程数设置为 1 时,我收到了更高的请求。这是日志

Attempt 1    => 86873
Attempt 2    => 107324
Attempt 3    => 97426
Attempt 4    => 94720
Attempt 5    => 97927
Attempt 6    => 94327
Attempt 7    => 94791

如您所见,它的峰值大约在 80,000 到 110,000 之间。当将其设置为高于 1(我尝试了 1 和 2)时,它甚至没有达到 80,000,它在 10 秒内达到大约 70-75000。我的想法是更多的线程=发送更多的数据,因为它在幕后做了更多的工作?谁能给我一些这方面的信息?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RDOS
{
    public class ThreadHandler
    {
        private int count = 0;
        private int threadCount = 3;
        private List<Thread> _threads = new List<Thread>();

        private string _ip;
        private int _port;

        public int RequestsSent;
        public int RequestsFailed;
        public DateTime Started;

        public ThreadHandler()
        {
            Console.Write("IP: ");
            _ip = Console.ReadLine();

            Console.Write("Port: ");
            _port = int.Parse(Console.ReadLine());

            Console.WriteLine("sending data to " + _ip + " on port " + _port);

            Thread backgroundThread = new Thread(new ThreadStart(OnBackgroundThread));
            backgroundThread.Start();

            for (int i = 0; i < threadCount; i++)
            {
                _threads.Add(new Thread(new ThreadStart(OnThread)));
            }

            foreach (Thread thread in _threads)
            {
                thread.Start();
            }
        }

        public void OnBackgroundThread()
        {
            Started = DateTime.Now;

            while (true)
            {
                System.Threading.Thread.Sleep(10000);
                TimeSpan span = DateTime.Now - Started;
                Console.WriteLine("Sent " + RequestsSent + " requests (running for " + span.TotalSeconds + ")");
                Console.ReadKey();
            }
        }

        public void OnThread()
        {
            IPEndPoint RHost = new IPEndPoint(IPAddress.Parse(_ip), _port);

            using (Socket socket = new Socket(RHost.AddressFamily, SocketType.Dgram, ProtocolType.Udp))
            {
                socket.Blocking = true;

                while (true)
                {
                    RequestsSent++;
                    byte[] buf = System.Text.Encoding.ASCII.GetBytes("fwkdkskdsksk");
                    socket.SendTo(buf, SocketFlags.None, RHost);
                }
            }
        }
    }
}

【问题讨论】:

  • 我对套接字了解不多,但我认为这可能是个问题socket.Blocking = true;
  • 老兄,你的测量代码有一个很大的缺陷,RequestsSent必须至少标记为volatile,否则.net会在调用之间缓存值,所以多个线程会看到以前的值和因此计数器没有按您预期的那样工作。即使使用 volatile 也会丢失一些值,最好在更新之前锁定值。
  • 写入Console 也会导致线程同步。 See here
  • @Amy 我在线程方法中看不到任何Console 写入
  • namespace RDOS...嗯。

标签: c# multithreading


【解决方案1】:

除了the thread safety error which is causing you to get lower than actual numbers,虽然你可能有多个线程但你仍然只有一个网络适配器,这很可能是你的瓶颈所在。

在 I/O 受限问题上投入更多 CPU 功率不会让您获得更快的 I/O,事实上,由于操作系统锁定带来的开销,大多数情况下它会导致您的 I/O 变慢要序列化对 I/O 设备的访问。获得更快 I/O 的唯一方法是获得更快的硬件。

【讨论】:

  • 那我最好只运行 1 个线程吗?另外,我将如何解决线程安全错误,锁定整个线程方法?
  • RequestsSent++; 替换为Interlocked.Increment(ref RequestsSent); 以修复线程安全错误。至于线程,我会从 1 开始,然后慢慢上升并测量速率,看看最佳位置在哪里。
猜你喜欢
  • 2019-04-26
  • 1970-01-01
  • 2013-03-19
  • 2016-04-06
  • 1970-01-01
  • 2011-06-09
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
相关资源
最近更新 更多