Недавно наблюдал довольно странное поведение, которое происходит только в Linux, но не во FreeBSD, и задавался вопросом, есть ли у кого-нибудь объяснение или хотя бы предположение о том, что на самом деле может происходить.
Проблема:
Метод создания сокета, socket.socket()
, иногда дает сбой.Это происходит только тогда, когда несколько потоков создают сокеты, однопоточный работает просто отлично.
Расширение на socket.socket()
не удается, в большинстве случаев я получаю сообщение об ошибке 13: «Отказано в доступе», но я такжезамечено «ошибка 93: протокол не поддерживается».
Примечания:
- Я пробовал это на Ubuntu 18.04 (ошибка есть) и freeBSD 12.0 (ошибкане существует)
- Это происходит только тогда, когда несколько потоков создают сокеты
- Я использовал UDP в качестве протокола для сокетов, хотя это кажется более отказоустойчивым.Я также попробовал это с TCP, он даже работает быстрее с подобными ошибками.
- Это случается только иногда, поэтому может потребоваться многократный запуск или, как в случае, который я указал ниже - раздутое число потоковследует также сделать трюк.
Код:
Вот некоторый минимальный код, который можно использовать для воспроизведения этого:
from threading import Thread
import socket
def foo():
udp = socket.getprotobyname('udp')
try:
send_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, udp)
except Exception as e:
print type(e)
print repr(e)
def main():
for _ in range(6000):
t = Thread(target=foo)
t.start()
main()
Примечание:
- Я использовал искусственно большое количество потоков, чтобы максимизировать вероятность того, что вы попадете в эту ошибку хотя бы один раз за циклс UDP.Как я уже говорил ранее, если вы попробуете TCP, вы увидите много ошибок с таким количеством потоков.Но на самом деле, даже большее количество потоков, например, 20 или даже 10, вызовет ошибку, вам, скорее всего, потребуется несколько прогонов, чтобы ее увидеть.
- Окружение создания сокета с помощью while,Попытка / исключение вызовет также сбой всех последующих вызовов.
- Окружение создания сокета с помощью попытки / исключить и с помощью бита «обработка исключений», перезапускающего функцию, то есть повторный вызов ее будет работать и не потерпит неудачу.
Любые идеи, предложения или объяснения приветствуются !!!
PS
Технически я знаю, что могу обойти мою проблему, создав одну нить для создания столько сокетовкак мне нужно, и передать их в качестве аргументов другим темам, но на самом деле это не главное.Меня больше интересует , почему это происходит и как ее решить, а не какие обходные пути могут быть, даже если они приветствуются.:)