networking - Разрешены ли параллельные вызовы send / recv в одном и том же сокете?




sockets (4)

Дескриптор сокета относится к процессу, а не к определенному потоку. Следовательно, можно отправлять / получать в / из одного и того же сокета в разных потоках, ОС будет обрабатывать синхронизацию.

Однако, если порядок отправки / получения семантически значим, вы сами (соответственно ваш код) должны обеспечить правильное упорядочение между операциями в разных потоках - как это всегда происходит с потоками.

  1. Можем ли мы называть send из одного потока и recv из другого в тот же сокет?
  2. Можно ли вызывать несколько отправлений параллельно из разных потоков в одном и том же сокете?

Я знаю, что хороший дизайн должен избегать этого, но я не понимаю, как будут работать эти системные API. Я тоже не могу найти хорошую документацию.

Любые указатели в направлении будут полезны.


Я не вижу, как получение в параллель могло бы что-то сделать. Если у вас есть сообщение с 3 байтами, 1 поток может получить 1-й 2 байта, а другой - последний байт, но вы не сможете сказать, что именно. Если ваши сообщения не являются длинными байтами, вы не можете надежно сделать что-либо работать с несколькими потоками.

Несколько отправлений могут работать, если вы отправили все сообщение за один раз, но я не уверен. Возможно, что можно перезаписать другой. Для этого не было бы никакой пользы от производительности.

Если необходимо отправить несколько потоков, вы должны реализовать синхронизированную очередь сообщений. Имейте один поток, который выполняет фактическую отправку, которая считывает сообщения из очереди, и другие потоки выдают целые сообщения. То же самое будет работать для получения, но поток приема должен знать формат сообщений, чтобы он мог десериализовать их должным образом.


POSIX определяет send / recv как атомные операции, поэтому, предполагая, что вы говорите о POSIX send / recv, тогда да, вы можете вызывать их одновременно из нескольких потоков, и все будет работать.

Это не обязательно означает, что они будут выполняться параллельно - в случае нескольких отправлений, второй, скорее всего, будет блокироваться до первого завершения. Вы, вероятно, этого не заметите, поскольку отправка завершается, как только он помещает свои данные в буфер сокета.

Если вы используете SOCK_STREAM сокеты, пытаясь сделать что-то параллельное, вряд ли будет полезно, поскольку send / recv может отправлять или получать только часть сообщения, что означает, что все может быть разделено.

Блокировка send / recv на SOCK_STREAM сокетах блокируется только до тех пор, пока они не отправят или не возвратят хотя бы 1 байт, поэтому разница между блокировкой и неблокированием не является полезной.


Несколько советов:

  1. Вставьте вставки / обновления в транзакцию.
  2. Для более старых версий SQLite - рассмотрите режим менее параноидального журнала ( pragma journal_mode ). Существует NORMAL , а затем есть OFF , что может значительно увеличить скорость вставки, если вы не слишком беспокоитесь о том, что база данных может быть повреждена, если ОС сбой. Если ваше приложение выходит из строя, данные должны быть точными. Обратите внимание, что в более новых версиях настройки OFF/MEMORY небезопасны для сбоев на уровне приложений.
  3. Игра с размерами страниц также имеет значение ( PRAGMA page_size ). Имея большие размеры страниц, вы можете сделать чтение и запись немного быстрее, поскольку в памяти хранятся более крупные страницы. Обратите внимание, что для вашей базы данных будет использоваться больше памяти.
  4. Если у вас есть индексы, подумайте о вызове CREATE INDEX после выполнения всех ваших вставок. Это значительно быстрее, чем создание индекса, а затем выполнение ваших вставок.
  5. Вы должны быть достаточно осторожны, если у вас есть одновременный доступ к SQLite, поскольку вся база данных заблокирована при выполнении записи, и, хотя возможны несколько считывателей, записи будут заблокированы. Это несколько улучшилось с добавлением WAL в новых версиях SQLite.
  6. Воспользуйтесь преимуществами экономии места ... более мелкие базы данных идут быстрее. Например, если у вас есть пары ключевых значений, попробуйте сделать ключ INTEGER PRIMARY KEY если это возможно, что заменит подразумеваемый уникальный столбец строк в таблице.
  7. Если вы используете несколько потоков, вы можете попробовать использовать кеш разделяемой страницы , который позволит обмениваться загружаемыми страницами между потоками, что позволяет избежать дорогостоящих вызовов ввода-вывода.
  8. Не используйте !feof(file) !

Я также задал подобные вопросы here и here .





c networking sockets