.exe 中的 Python 子进程

标签 python python-2.7 python-3.x network-programming subprocess

我正在创建一个 python 脚本,它将通过网络复制文件和文件夹。它是跨平台的,所以我使用 cx_freeze

创建了一个 .exe 文件

我使用了subprocess模块​​的Popen方法

如果我运行 .py 文件,它会按预期运行,但是当我创建 .exe 子进程时系统中没有创建

我已经浏览了 subprocess 模块的所有文档,但没有找到任何解决方案

其他一切(我使用的 Tkinter 也能正常工作)在 .exe accept 子进程中工作。

知道如何在 .exe.file 中调用子进程吗??

这个文件正在调用另一个 .py 文件

def start_scheduler_action(self, scheduler_id, scheduler_name, list_index):
       scheduler_detail=db.get_scheduler_detail_using_id(scheduler_id)
        for detail in scheduler_detail:
            source_path=detail[2]
        if not os.path.exists(source_path):
            showerror("Invalid Path","Please select valid path", parent=self.new_frame)
            return

        self.forms.new_scheduler.start_scheduler_button.destroy()

        #Create stop scheduler button
        if getattr(self.forms.new_scheduler, "stop_scheduler_button", None)==None:

            self.forms.new_scheduler.stop_scheduler_button = tk.Button(self.new_frame, text='Stop scheduler', width=10, command=lambda:self.stop_scheduler_action(scheduler_id, scheduler_name, list_index))
            self.forms.new_scheduler.stop_scheduler_button.grid(row=11, column=1, sticky=E, pady=10, padx=1)

        scheduler_id=str(scheduler_id)

        # Get python paths
        if sys.platform == "win32":
            proc = subprocess.Popen(['where', "python"], env=None, stdout=subprocess.PIPE)

        else:
            proc = subprocess.Popen(['which', "python"], env=None,stdout=subprocess.PIPE)

        out, err = proc.communicate()

        if err or not out:
            showerror("", "Python not found", parent=self.new_frame)

        else:

            try:
                paths = out.split(os.pathsep)

                # Create python path
                python_path = (paths[len(paths) - 1]).split('\n')[0]

                cmd = os.path.realpath('scheduler.py')
                #cmd='scheduler.py'

                if sys.platform == "win32":
                    python_path=python_path.splitlines()

                else:
                    python_path=python_path

                # Run the scheduler file using scheduler id

                proc = subprocess.Popen([python_path, cmd, scheduler_id], env=None, stdout=subprocess.PIPE)


                message="Started the scheduler : %s" %(scheduler_name)
                showinfo("", message, parent=self.new_frame)

                #Add process id to scheduler table
                process_id=proc.pid
                #showinfo("pid", process_id, parent=self.new_frame)
                def get_process_id(name):
                    child = subprocess.Popen(['pgrep', '-f', name], stdout=subprocess.PIPE, shell=False)
                    response = child.communicate()[0]
                    return [int(pid) for pid in response.split()]

                print(get_process_id(scheduler_name))

                # Add the process id in database
                self.db.add_process_id(scheduler_id, process_id)

                # Add the is_running status in database
                self.db.add_status(scheduler_id)

            except Exception as e:

                showerror("", e)

这个文件叫做:

def scheduler_copy():

    date= strftime("%m-%d-%Y %H %M %S", localtime())
    logFile = scheduler_name + "_"+scheduler_id+"_"+ date+".log"
    #file_obj=open(logFile, 'w')

    # Call __init__ method of xcopy file 
    xcopy=XCopy(connection_ip, username , password, client_name, server_name, domain_name)
    check=xcopy.connect()

    # Cretae a log file for scheduler
    file_obj=open(logFile, 'w')

    if check is False:

        file_obj.write("Problem in connection..Please check connection..!!")
        return

    scheduler_next_run=schedule.next_run()
    scheduler_next_run="Next run at: " +str(scheduler_next_run)

    # If checkbox_value selected copy all the file to new directory
    if checkbox_value==1:
        new_destination_path=xcopy.create_backup_directory(share_folder, destination_path, date)
    else:
        new_destination_path=destination_path

    # Call backup method for coping data from source to destination
    try:
        xcopy.backup(share_folder, source_path, new_destination_path, file_obj, exclude)
        file_obj.write("Scheduler completed successfully..\n")

    except Exception as e:

        # Write the error message of the scheduler to log file
        file_obj.write("Scheduler failed to copy all data..\nProblem in connection..Please check connection..!!\n")
        # #file_obj.write("Error while scheduling")
        # return

    # Write the details of scheduler to log file
    file_obj.write("Total skipped unmodified file:")
    file_obj.write(str(xcopy.skipped_unmodified_count))
    file_obj.write("\n")
    file_obj.write("Total skipped file:")
    file_obj.write(str(xcopy.skipped_file))
    file_obj.write("\n")
    file_obj.write("Total copied file:")
    file_obj.write(str(xcopy.copy_count))
    file_obj.write("\n")
    file_obj.write("Total skipped folder:")
    file_obj.write(str(xcopy.skipped_folder))
    file_obj.write("\n")
    # file_obj.write(scheduler_next_run)
    file_obj.close()

最佳答案

您的源代码中有些尴尬,但我不会花时间在这上面。例如,如果您想找到 source_path,最好使用带有 break/elsefor 循环:

for detail in scheduler_detail:
    source_path = detail[2]
    break  # found
else:
    # not found: raise an exception
    ...

一些建议:

  • 尽量将用户界面代码和子处理分开,避免将两者混合。
  • 使用异常和异常处理程序。
  • 如果你想要可移植的代码:避免系统调用(Windows 上没有 pgrep)。

由于您的应用程序打包在 virtualenv 中(我假设 cx_freeze 执行此类操作),您无法访问系统范围的 Python。你甚至在 Windows 上都没有。因此,您需要使用打包的 Python(无论如何,这是最佳实践)。

如果你想像子进程一样调用 Python 脚本,这意味着你有两个打包的应用程序:你需要为主应用程序创建一个 exe 和为 创建 scheduler.py 脚本。但是,与它沟通并不容易。

另一种解决方案是使用 multiprocessing 生成一个新的 Python 进程。由于您不想等待处理结束(这可能很长),因此您需要创建守护进程。 multiprocessing 中解释了这样做的方法。模块。

基本上:

import time
from multiprocessing import Process

def f(name):
    print('hello', name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.daemon = True
    p.start()

    # let it live and die, don't call: `p.join()`
    time.sleep(1)

当然,我们需要根据您的问题进行调整。

以下是我的做法(为清楚起见,我删除了与 UI 相关的代码):

import scheduler


class SchedulerError(Exception):
    pass


class YourClass(object):
    def start_scheduler_action(self, scheduler_id, scheduler_name, list_index):
        scheduler_detail = db.get_scheduler_detail_using_id(scheduler_id)
        for detail in scheduler_detail:
            source_path = detail[2]
            break
        else:
            raise SchedulerError("Invalid Path", "Missing source path", parent=self.new_frame)

        if not os.path.exists(source_path):
            raise SchedulerError("Invalid Path", "Please select valid path", parent=self.new_frame)

        p = Process(target=scheduler.scheduler_copy, args=('source_path',))
        p.daemon = True
        p.start()

        self.db.add_process_id(scheduler_id, p.pid)

要检查您的进程是否仍在运行,我建议您使用 psutil .这真是一个很棒的工具!

您可以像这样定义您的 scheduler.py 脚本:

def scheduler_copy(source_path):
    ...

多处理与线程 Python

引用这个答案:https://stackoverflow.com/a/3044626/1513933

The threading module uses threads, the multiprocessing module uses processes. The difference is that threads run in the same memory space, while processes have separate memory. This makes it a bit harder to share objects between processes with multiprocessing. Since threads use the same memory, precautions have to be taken or two threads will write to the same memory at the same time. This is what the global interpreter lock is for.

在这里,多处理相对于多线程的优势在于您可以杀死(或终止)一个进程;你不能杀死一个线程。为此,您可能需要 psutil。

关于.exe 中的 Python 子进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46537800/

相关文章:

python - scrapy没有选择下拉选项

python - 链接 : fatal error LNK1104: cannot open file 'python27.lib'

python - 如何强制自己更优雅地编码?

Python:有策略地遍历 0-9 的十位数字

python - 通过在单个记录中多次出现嵌套键进行分组

python - 如何为新笔记本在 Jupyter 笔记本上切换环境?

javascript - 使用 MySQL 和 Python 通过 webapp(PHP,javascript)控制串口

Python 2.7,在字符串的最后两位数字前添加破折号

python-2.7 - 如何在 Keras 中使用 log_loss 作为指标?

python - 使用 call_soon() 和 ensure_future() 的区别