Как устранить / обойти проблему блокировки, которая, по-видимому, связана с GIL

Непонятная блокировка между двумя потоками, похоже, связана с глобальной блокировкой интерпретатора или какой-то другой «скрытой блокировкой», и я не понимаю, как продолжить устранение неполадок. Любые советы, как устранить блокировку, будут оценены.

Проблема воспроизводится (хаотично и в некоторой степени случайным образом) в более крупном наборе кода. Код строго на питоне. Версия Python - 2.6.5 (в Linux). Часы устранения неполадок уменьшили проблему, когда происходит блокировка, до следующего:

  1. Программа имеет только два запущенных потока
  2. Потоки одновременно вызывают метод, защищенный одним потоком.RLock
  3. Поток 1 получил блокировка [плюс несколько других блокировок] через Acquire ()
  4. Поток 2 вызвал acqu () и подтвердил, что ожидает блокировки
  5. Поток 1 может выполнять печать на консоль с помощью print (), однако он блокируется простым неблокирующим вызовом библиотеки

Оскорбительный вызов в # 5 - это функция unicode.encode, которая должна быть неблокирующей. Следующий код в потоке 1 в позиции, где блокируется поток, будет (как и ожидалось) напечатать 'A' и 'B':

print('A')
print('B')

Однако следующий код просто напечатает 'A' и заблокирует поток:

print('A')
u'hello'.encode('utf8') # This dummy (non-blocking) call locks up Thread 1
print('B')

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

Есть мысли, как устранить эту неполадку в дальнейшем, или какие-либо механизмы, позволяющие каким-то образом контролировать или манипулировать операцией GIL в качестве обходного пути?

Edit: Некоторая дополнительная информация в ответ на смещение выборки (и спасибо за ответ). У меня возникли проблемы с получением трассировки, поскольку проблема, кажется, очень чувствительна ко всему, что может нарушить синхронизацию между двумя потоками. Однако, запустив strace только с опцией -f, после нескольких итераций мне удалось получить трассировку.

Поток 1 содержит эти три оператора отладки, которые должны выводить на консоль две строки «CHECK_IN» и «CHECK_TEST»:

print('CHECK IN')#DEBUG
u'hello'.encode('utf8')
print('CHECK TEST')#DEBUG

Вот последняя страница strace:

8605  mmap2(NULL, 266240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb753d000
8605  mmap2(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xb6d3c000
8605  mprotect(0xb6d3c000, 4096, PROT_NONE) = 0
8605  clone(child_stack=0xb753c494, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb753cbd8, {entry_number:6, base_addr:0xb753cb70, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb753cbd8) = 8606
8606  set_robust_list(0xb753cbe0, 0xc <unfinished ...>
8605  futex(0xa239138, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606  <... set_robust_list resumed> )   = 0
8606  futex(0xa239138, FUTEX_WAKE_PRIVATE, 1) = 1
8605  <... futex resumed> )             = 0
8606  gettimeofday( <unfinished ...>
8605  futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606  <... gettimeofday resumed> {1301528807, 326496}, NULL) = 0
8606  futex(0xa272398, FUTEX_WAKE_PRIVATE, 1) = 1
8605  <... futex resumed> )             = 0
8606  futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8605  gettimeofday( <unfinished ...>
8606  <... futex resumed> )             = 0
8605  <... gettimeofday resumed> {1301528807, 326821}, NULL) = 0
8606  futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8605  futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8606  <... futex resumed> )             = -1 EAGAIN (Resource temporarily unavailable)
8605  <... futex resumed> )             = 0
8606  gettimeofday( <unfinished ...>
8605  futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606  <... gettimeofday resumed> {1301528807, 326908}, NULL) = 0
8606  futex(0xa272398, FUTEX_WAKE_PRIVATE, 1) = 1
8605  <... futex resumed> )             = 0
8606  futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8605  futex(0xa1b0d70, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606  <... futex resumed> )             = 0
8606  stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
8606  fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
8606  mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6d3b000
8606  write(1, "CHECK IN\n", 9)         = 9
8606  futex(0xa115270, FUTEX_WAIT_PRIVATE, 0, NULL

И вывод трех строк кода до блокировки программы выглядит следующим образом:

CHECK IN

Итак, strace показывает, как поток 1 (# 8606) записывает ' CHECK_IN ', а при достижении юникода. вызов encode переходит в состояние ожидания, которое никогда не возвращается.

Между прочим, я делаю пару будущих операций импорта во всех модулях, чтобы придерживаться некоторых новых соглашений Python ...

from __future__ import print_function, unicode_literals

... но я не вижу, что они должны делать какие-либо разница - особенно потому, что строка u'hello 'явно вызывается как строка Unicode.

6
задан CptJeanLuc 31 March 2011 в 00:09
поделиться