Я программирую какую-то "openvpn-like" вещь и думал, что это будет хороший кандидат для улучшения моего знания Haskell. Однако я столкнулся с довольно серьезными проблемами с производительностью.
Что он делает: он открывает устройство TUN; он связывается с UDP-портом, запускает 2 потока (forkIO, однако скомпилированный с помощью -threaded из-за fdRead). Я не использовал пакет tuntap и сделал это сам полностью в Haskell.
поток 1: прочитайте пакет (fdRead) с устройства tun. Отправьте его с помощью UDP-сокета.
thread 2: прочитать пакет (recv) из сокета UDP; отправьте его на устройство tun (fdWrite)
Проблема 1: В этой конфигурации fdRead возвращает String, и я использовал функции Network.Socket, которые принимают String. Я сделал конфигурацию на локальной системе (магия iptables), и я могу запустить 15 МБ/с через localhost, программа запускается в основном на 100% процессоре. Это медленно. Я могу что-то сделать, чтобы улучшить производительность?
Проблема 2: мне нужно будет что-то добавить к пакетам, которые я отправляю; однако функция сети sendMany принимает только ByteString; чтение из Fd возвращает String. Конверсия довольно медленная. Преобразование в Handle, похоже, не работает достаточно хорошо с устройством TUN....
Проблема 3: Я хотел сохранить некоторую информацию в Data.Heap(функциональная куча) (мне нужно использовать "takeMin", и хотя для 3-х элементов это слишком много, это легко сделать:)). Поэтому я создал MVar и на каждом полученном пакете я вытащил кучу из MVar, обновил кучу с новой информацией и вернул ее inito MVar. Теперь вещь просто начинает есть МНОГО памяти. Наверное, потому что старые кучи не собирают мусор в скором времени/достаточно часто.?
Есть ли способ решить эти проблемы или мне нужно вернуться к C...? То, что я делаю, должно быть в основном законсервировано - я использую неправильные библиотеки для его достижения?
==================
Что я сделал: - при установке на MVar, сделал:
a `seq` putMVar mvar a
Это отлично справилось с утечкой памяти.
- изменено на ByteString; теперь я получаю 42 МБ/с при использовании только "чтения/записи" без дальнейшей обработки. Версия C составляет около 56 МБ/с, поэтому это приемлемо.