在Python中长时间运行时为用户打印消息

时间:2019-03-21 12:13:07

标签: python multithreading pandas

我有一个熊猫操作需要很长时间,因为xlsx文件很大,可以导入到数据框中。我想通知用户,他必须在任务运行时等待,但我无法做到这一点。这是我的功能:

def create_list_of_data():
    list_data_all = []
    list_files_xlsx_f = create_list_of_xlsx()

    for xls_files in list_files_xlsx_f:        
        df = pandas.read_excel(xls_files)      
        df = df[["COL1", "COL2"]]
        list_data = df.values.tolist()
        list_data_all.extend(list_data)
    return list_data_all 

我尝试的是使用线程:

import itertools
import threading
import time
import sys

#here is the animation
def animate():
    for c in itertools.cycle(['|', '/', '-', '\\']):
        if done:
            break
        sys.stdout.write('\rloading ' + c)
        sys.stdout.flush()
        time.sleep(0.1)
    sys.stdout.write('\rDone!     ')


 def create_list_of_data():
    list_data_all = []
    list_files_xlsx_f = create_list_of_xlsx()

    for xls_files in list_files_xlsx_f: 
        done = False
        t = threading.Thread(target=animate)
        t.start()
        df = pandas.read_excel(xls_files)
        done = True         
        df = df[["COL1", "COL2"]]
        list_data = df.values.tolist()
        list_data_all.extend(list_data)
    return list_data_all 

我的问题是,动画函数无法识别“完成”变量。也许这不是正确的方法。有什么想法吗?

函数create_list_of_data()从另一个的PySide按钮启动 文件。

5 个答案:

答案 0 :(得分:1)

如果将布尔值与对象包装在一起,则可以按引用而不是按值传递

import itertools
import threading
import time
import sys

#here is the animation
def animate(holder):
    for c in itertools.cycle(['|', '/', '-', '\\']):
        if holder.done:
            break
        sys.stdout.write('\rloading ' + c)
        sys.stdout.flush()
        time.sleep(0.1)
    sys.stdout.write('\rDone!     ')

def create_list_of_data():
    list_data_all = []

    class Holder(object):
        done = False

    holder = Holder()
    t = threading.Thread(target=animate, args=(holder,))
    t.start()
    time.sleep(10) #Simulating long job
    holder.done = True         
    return list_data_all 

我稍微修改了示例,以便无需额外的功能即可运行它。

答案 1 :(得分:1)

您应该在函数外部定义“完成”,以便它是全局变量。这样,两个功能都可以访问它。试试这个:

import itertools
import threading
import time
import sys

done = False

#here is the animation
def animate():
    for c in itertools.cycle(['|', '/', '-', '\\']):
        if done:
            break
        sys.stdout.write('\rloading ' + c)
        sys.stdout.flush()
        time.sleep(0.1)
    sys.stdout.write('\rDone!     ')


 def create_list_of_data():
    list_data_all = []
    list_files_xlsx_f = create_list_of_xlsx()

    for xls_files in list_files_xlsx_f: 
        done = False
        t = threading.Thread(target=animate)
        t.start()
        df = pandas.read_excel(xls_files)
        done = True         
        df = df[["COL1", "COL2"]]
        list_data = df.values.tolist()
        list_data_all.extend(list_data)
    return list_data_all 

答案 2 :(得分:1)

基本上,您需要在其他线程处于活动状态时显示loading *

import sys
import time
import itertools
import threading


def long_process():
    time.sleep(5)


thread = threading.Thread(target=long_process)
thread.start()
for c in itertools.cycle(['|', '/', '-', '\\']):
    sys.stdout.write('\rloading ' + c)
    sys.stdout.flush()
    time.sleep(0.1)
    if not thread.isAlive():
        break
sys.stdout.write('\rDone!     ')

输出:

enter image description here

答案 3 :(得分:0)

您可以使用多处理而非线程化,并在单独的进程中启动动画和创建函数_create_list_of_data。 这样的事情应该起作用。

import time
import multiprocessing as mp


def countdown(seconds, message):
    while seconds:
        mins, secs = divmod(int(seconds), 60)
        timeformat = '{:02d}:{:02d} '.format(mins, secs)
        print(timeformat + message, end='\r')
        time.sleep(1)
        seconds -= 1

def slowFunction(seconds):
    print('Begin')
    time.sleep(seconds)
    print('Done')



q = mp.Queue()
countdownProcess = mp.Process(target=countdown, args=(10, 'loading...'))
slowProcess = mp.Process(target=slowFunction, args=(10, ))
countdownProcess.start()
slowProcess.start()
countdownProcess.join()
slowProcess.join()

答案 4 :(得分:0)

您可以使用队列将完成的值发送到线程:

import itertools
import threading
from queue import Queue
import time
import sys

#here is the animation
def animate(q):
    for c in itertools.cycle(['|', '/', '-', '\\']):
        done = q.get()
        if done:
            break
        sys.stdout.write('\rloading ' + c)
        sys.stdout.flush()
        time.sleep(0.1)
    sys.stdout.write('\rDone!     ')


def create_list_of_data():
    list_data_all = []
    list_files_xlsx_f = create_list_of_xlsx()
    queue = Queue()

    for xls_files in range(1,1000):
        done = False
        queue.put(done)
        t = threading.Thread(target=animate, args=(queue,))
        t.start()
        df = pandas.read_excel(xls_files)
        done = True
        queue.put(done)
        df = df[["COL1", "COL2"]]
        list_data = df.values.tolist()
        list_data_all.extend(list_data)
    return list_data_all