Почему `xclip .bashrc` занимает намного больше времени, чем system(xclip .bashrc) в ruby?

irb(main):001:0> require 'benchmark'
=> true
irb(main):002:0> puts Benchmark.measure { system "xclip .bashrc" }
  0.000000   0.000000   0.000000 (  0.008030)
=> nil
irb(main):003:0> puts Benchmark.measure { `xclip .bashrc` }
  0.000000   0.000000   0.000000 ( 33.215158)
=> nil
irb(main):004:0> RUBY_VERSION
=> "2.0.0"

Я прочитал почти все в Интернете о различных способах вызова команды оболочки из скрипта ruby, но я просто не могу понять, почему Kernel#` занимает намного больше времени, чем Kernel#system.

Обновление:

Kernel#` намного медленнее только с xclip. Все остальные команды занимают почти столько же времени.


person toctan    schedule 08.10.2013    source источник
comment
@platzhirsch xclip ничего не выводит на стандартный вывод, это не объясняет, почему одна xclip намного медленнее с обратной кавычкой, а другая команда, такая как cat, работает совершенно нормально.   -  person toctan    schedule 08.10.2013


Ответы (2)


Я сомневаюсь, что xclip просто требует много времени для завершения, когда вы используете обратные кавычки, чтобы раскошелиться. Это связано с выбором. Без какого-либо выбора, предоставленного через -sel, по умолчанию будет XA_PRIMARY, который обычно используется для копирования и вставки с помощью средней кнопки мыши.

Когда вы бежите

$ xclip text.txt

содержимое становится доступным через XA_PRIMARY, что означает, что вы можете вставить его с помощью средней кнопки мыши или $ xclip -o. Это начинает становиться странным, когда вы запускаете его через оболочку в Ruby:

ruby -e '`xclip text.txt`

Это никогда не заканчивается, если вы ничего не делаете. Он завершается, когда вы выбираете что-то в своей системе X11, например, в консоли или где-либо еще. Просто выделение, пометка чего-то мышкой. Если вы этого не сделаете, в какой-то момент он зависнет и / или истечет время ожидания.

Такое же поведение можно наблюдать при использовании подробного режима:

$ xclip -verbose text.txt

Connected to X server.
Using UTF8_STRING.
Reading text.txt...
Waiting for selection requests, Control-C to quit
  Waiting for selection request number 1

Запрос на выбор, опять же, обслуживается, когда вы что-то выбираете.

Хорошим инструментом анализа для этого является strace (опция -f также предназначена для отслеживания веток)

$ strace -f ruby -e '`xclip text.txt`'

...
poll([{fd=3, events=POLLIN|POLLOUT}], 1, 4294967295) = 1 ([{fd=3, revents=POLLOUT}])
writev(3, [{"\20\0\3\0\4\0\200\2INCR", 12}, {NULL, 0}, {"", 0}], 3) = 12
poll([{fd=3, events=POLLIN}], 1, 4294967295) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "\1\0\f\0\0\0\0\0\235\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096,                                                                      0, NULL, NULL) = 32
recvfrom(3, 0x165e964, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(3, 0x165e964, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=3, events=POLLIN}], 1, 4294967295

В последней строке висит до тех пор, пока не будет сделан выбор. poll() используется для ожидания события файла в файловом дескрипторе. В какой-то момент он завершится, но 4 294 967 295 мс — это довольно долго. То же самое можно проследить только с strace -f xclip text.txt.

Вы можете взглянуть на файловые дескрипторы через ls -l /proc/PID/fd. Один с номером 3 — это файловый дескриптор, где xclip ожидает вашего выбора.

Что делает его таким трудным для отладки, так это то, что if мгновенно завершается с strace xclip text.txt, но не с strace -f text.txt. В тот момент, когда вы хотите проследить вилку, она больше не работает. Это та же проблема, что и у вас с Ruby. Он пытается отследить вывод, потому что Kernel#` хочет вернуть вывод. Вероятно, это также связано с заявкой #9 Не закрытие стандартного вывода при настройке буфера обмена из стандартного ввода.

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

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

person Konrad Reiche    schedule 08.10.2013

Вам нужно предоставить более подробную информацию о том, что вы делаете с xclip. B/c (потому что) мой ruby ​​1.9.3 с использованием "echo hello" показывает минимальную разницу.

$ irb
irb(main):001:0> require 'benchmark'
=> true
irb(main):002:0> puts Benchmark.measure {  `echo hello` }
  0.000000   0.000000   0.000000 (  0.001471)
=> nil
irb(main):003:0> puts Benchmark.measure { system "echo hello" }
hello
  0.000000   0.000000   0.000000 (  0.001598)
=> nil
irb(main):004:0> RUBY_VERSION
=> "1.9.3"
person ChuckCottrill    schedule 08.10.2013
comment
Я просто пытаюсь манипулировать буфером обмена Linux с помощью xclip. echo тоже нормально работает в моей системе, просто xclip намного медленнее с обратной кавычкой. - person toctan; 08.10.2013
comment
Вы можете несколько раз попробовать изменить порядок системных вызовов Kernel#` и Kernel#, а также протестировать это несколько раз. Вероятно, вы смотрите на тайминг из xclip, а не из Ruby. - person ChuckCottrill; 08.10.2013
comment
Я застрял на этой проблеме в течение нескольких часов, поверьте мне, я проверял это много раз, только сейчас я проверил это на компьютере моего друга, тот же результат: system "xclip file" супер быстро, как будто введите его в терминале, а затем нажмите RET, `xclip file` занимает десятки секунд, и становится медленнее, когда файл становится больше. - person toctan; 08.10.2013
comment
Извините, но это скорее комментарий, а не ответ. - person Konrad Reiche; 08.10.2013