繁体   English   中英

.exe中的Python子进程

[英]Python subprocess in .exe

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

我使用了子进程模块的Popen方法

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

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

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

任何想法如何在.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(无论如何这是最佳实践)。

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

另一种解决方案是使用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

threading模块使用线程, multiprocessing模块使用进程。 不同之处在于线程在相同的内存空间中运行,而进程具有单独的内存。 这使得在具有多处理的进程之间共享对象变得有点困难。 由于线程使用相同的内存,因此必须采取预防措施,否则两个线程将同时写入同一内​​存。 这就是全局解释器锁的用途。

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

这不是您正在寻找的确切解决方案,但出于两个原因,应优先考虑以下建议。

  1. 这些都是更加蟒蛇的方式
  2. subprocess略贵

建议你可以考虑

  1. 不要使用子进程来获取系统路径。 尝试检查os.getenv('PATH')以获取env变量并尝试查找python是否在路径中。 对于Windows,必须手动添加Python路径,否则您可以直接签入Program Files

  2. 要检查进程ID,您可以尝试psutils 这里提供了一个很好的答案, 我如何在Python中获取进程列表?

  3. 从python脚本调用另一个脚本。 这看起来不酷。 不错,但我根本不喜欢这个。

  4. 在上面的代码中,line - if sys.platform == "win32": ifelse condition ==>中的值相同,这里不需要条件语句。

你写了很好的工作代码来告诉你。 保持编码!

如果要在exe文件中运行子进程,则可以使用

import subprocess

program=('example')
arguments=('/command')
subprocess.call([program, arguments])

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM