Как разветвить процесс пошел?
Я хочу развилить процесс go и получить обратно идентификатор нового процесса (ов), но все, что я могу увидеть в библиотеках exec
или os
, - это запустить новый процесс.
2 ответа:
Вы якобы хотите
Обратите внимание, чтоsyscall.ForkExec()
отsyscall
пакет.fork()
был изобретен в то время, когда вообще не использовались потоки, а процесс всегда имел только один поток выполнения, и поэтому разветвление было безопасным. С Go ситуация радикально отличается, так как он активно использует потоки уровня операционной системы для управления своим расписанием goroutine.Теперь, без украшений
А теперь подумайте о проблеме подробнее. Я бы сказал, что в наши дни только прямой звонок tofork(2)
в Linux дочерний процесс будет иметь только один поток- тот, который вызвалfork(2)
в Родительском процессе-среди всех тех, которые были активны, включая некоторые важные потоки, используемые средой выполнения Go. В основном это означает, что вы просто не можете ожидать, что дочерний procss сможет продолжить выполнение кода Go, и единственное, что вы можете разумно сделать, - это каким-то образом немедленно выполнитьexec(2)
. Обратите внимание, что именно для этогоsyscall.ForkExec()
предполагается использовать.fork(2)
полезен для is "наилучшего асинхронного процесса snapshotting состояния" - типа, скажем, Redis использует. Этот метод основан на том, что дочерний процесс наследует все страницы данных памяти от своего родителя, но ОС использует метод копирования при записи, чтобы не копировать все эти данные, поэтому ребенок может просто сидеть там и сохранять все структуры данных на диск, пока его родитель пыхтит, изменяя их в своем собственном адресном пространстве. Любое другое мыслимое использование дляfork()
подразумевает немедленноеexec()
, и это то, для чегоexec.Command()
и др., Так почему бы просто не использовать его?
Одним из решений является использование
exec.Command
, выполненного в его goroutine.Вот что такое маленький проект
akshaydeo/go_process
делает:// Method to fork a process for given command // and return ProcessMonitor func Fork(processStateListener ProcessStateListener, cmdName string, cmdArgs ...string) { go func() { processMonitor := &ProcessMonitor{} args := strings.Join(cmdArgs, ",") command := exec.Command(cmdName, args) output, err := command.Output() if err != nil { processMonitor.Err = err processStateListener.OnError(processMonitor, err) } processMonitor.Output = &output processStateListener.OnComplete(processMonitor) }() }
Испытание
process_test.go
показывает несколько примеров:// Test case for fork func TestFork(t *testing.T) { processStateListenerImpl := &ProcessStateListenerImpl{make(chan bool)} Fork(processStateListenerImpl,"ls", "-a") //("ping","192.168.3.141","-c","3") // waiting onto monitor <-processStateListenerImpl.monitor }