Ответ , а также другие ответы правильные. Я собираюсь добавить к этим ответам решение, которое, я думаю, будет полезно. Я думаю, что это часто возникает при программировании. Следует отметить, что для коллекций (списки, наборы и т. Д.) Основной проблемой является добавление в коллекцию. Вот где вещи ломаются. Даже удаление в порядке.
В большинстве случаев мы можем использовать Collection extends T>
, а не Collection
, и это должен быть первый выбор. Однако я нахожу случаи, когда это непросто сделать. Он обсуждает вопрос о том, всегда ли это самое лучшее. Я представляю здесь класс DownCastCollection, который может преобразовать Collection extends T>
в Collection
(мы можем определить аналогичные классы для List, Set, NavigableSet, ..), которые будут использоваться, когда использование стандартного подхода очень неудобно. Ниже приведен пример того, как его использовать (мы могли бы также использовать Collection extends Object>
в этом случае, но я просто не могу проиллюстрировать использование DownCastCollection.
/**Could use Collection extends Object> and that is the better choice.
* But I am doing this to illustrate how to use DownCastCollection. **/
public static void print(Collection
Теперь класс:
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class DownCastCollection extends AbstractCollection implements Collection {
private Collection extends E> delegate;
public DownCastCollection(Collection extends E> delegate) {
super();
this.delegate = delegate;
}
@Override
public int size() {
return delegate ==null ? 0 : delegate.size();
}
@Override
public boolean isEmpty() {
return delegate==null || delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
if(isEmpty()) return false;
return delegate.contains(o);
}
private class MyIterator implements Iterator{
Iterator extends E> delegateIterator;
protected MyIterator() {
super();
this.delegateIterator = delegate == null ? null :delegate.iterator();
}
@Override
public boolean hasNext() {
return delegateIterator != null && delegateIterator.hasNext();
}
@Override
public E next() {
if(!hasNext()) throw new NoSuchElementException("The iterator is empty");
return delegateIterator.next();
}
@Override
public void remove() {
delegateIterator.remove();
}
}
@Override
public Iterator iterator() {
return new MyIterator();
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
if(delegate == null) return false;
return delegate.remove(o);
}
@Override
public boolean containsAll(Collection> c) {
if(delegate==null) return false;
return delegate.containsAll(c);
}
@Override
public boolean addAll(Collection extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection> c) {
if(delegate == null) return false;
return delegate.removeAll(c);
}
@Override
public boolean retainAll(Collection> c) {
if(delegate == null) return false;
return delegate.retainAll(c);
}
@Override
public void clear() {
if(delegate == null) return;
delegate.clear();
}
}
Вы должны использовать subprocess.Popen
вместо subprocess.call
.
Что-то вроде:
subprocess.Popen(["python", "slave.py"] + sys.argv[1:])
Из документов в subprocess.call
:
Запустите команду, описанную args. Подождите, пока команда завершится, а затем верните атрибут returncode.
blockquote>(Также не используйте список для передачи в аргументах, если вы собираетесь использовать
shell = True
).
Вот пример MCVE1, демонстрирующий неблокирующий вызов суперпроцесса:
import subprocess import time p = subprocess.Popen(['sleep', '5']) while p.poll() is None: print('Still sleeping') time.sleep(1) print('Not sleeping any longer. Exited with returncode %d' % p.returncode)
Альтернативный подход, основанный на более поздних изменениях языка python для обеспечения совместного использования основанный на параллелизме:
# python3.5 required but could be modified to work with python3.4. import asyncio async def do_subprocess(): print('Subprocess sleeping') proc = await asyncio.create_subprocess_exec('sleep', '5') returncode = await proc.wait() print('Subprocess done sleeping. Return code = %d' % returncode) async def sleep_report(number): for i in range(number + 1): print('Slept for %d seconds' % i) await asyncio.sleep(1) loop = asyncio.get_event_loop() tasks = [ asyncio.ensure_future(do_subprocess()), asyncio.ensure_future(sleep_report(5)), ] loop.run_until_complete(asyncio.gather(*tasks)) loop.close()
1 Проверено на OS-X с использованием python2.7 & amp; python3.6
Здесь три уровня тщательности.
Как утверждает Миллилсон, если вы просто замените subprocess.call
на subprocess.Popen
, оставив все остальное одинаковым, то main.py не будет ждать ведомого. чтобы закончить до его продолжения. Этого может быть достаточно. Если вы заботитесь о зомби-процессах , висящих вокруг, вы должны сохранить объект, возвращенный из subprocess.Popen
, а в какой-то более поздний момент вызывать его метод wait
. (Зомби автоматически уйдут, когда main.py выйдет, поэтому это серьезная проблема, если main.py работает очень долго и / или может создавать много подпроцессов.) И, наконец, если вы не хотите зомби но вы также не хотите решать, где делать ожидание (это может быть целесообразно, если оба процесса запускаются в течение длительного и непредсказуемого времени после этого), используйте библиотеку python-daemon , чтобы подчинить подчиненную функцию disassociate сам от мастера - в этом случае вы можете продолжить использование subprocess.call
в главном устройстве.