初学Python:多线程脚本-使用Thread类创建,给构造函数传递回调对象(第一种)

个人比较习惯这种写法

举个简单的场景:
有一批图片和图片对应的list,现在需要将符合特定要求的图片拷贝到另一个路径下,采用多线程处理,代码如下(备注:只展示简单的代码框架,主要是理解queue和threading的写法,具体内容还得靠自己写):

使用Thread类创建,给构造函数传递回调对象

# /usr/bin/python
# -*- coding:utf-8 -*-

import os, json, time
from Queue import Queue
import threading, shutil

pic_list = 'pic.list'
target_dir = 'target_pic'
DEFAULT_THREAD_NUM = 20

#######################################
#文件夹是否存在
def wheather_dir_exists(path):

    try:
        os.makedirs(path)
    except OSError:
        if not os.path.isdir(path):
            raise


def generate_dict():
    
    m = 0
    dict1 = {}
    dict2 = {}
    ...
    此处代码省略
    ...
    return dict1
    
#定义一个函数,函数里再定义个拷贝图片函数,调用generate_copy_func()可以返回一个拷贝图片函数
def generate_copy_func():
    global pic_dir
    global target_dir
    def copy_func(value, dict3):
        for k in range(len(value)):
            try:
                pic_key = value[k]
                pic_dir = dict3[pic_key] 
                shutil.copy(pic_dir, target_dir)
                #os.system('cp ' + pic_dir + ' ' + target_dir)
            except:
                continue
    return copy_func

#定义一个work函数
def work(queue, func, need_dict, sum_queue):
    while True:
        arg = queue.get()
        func(arg, need_dict)
        queue.task_done()
        s = queue.qsize()
        if s%100 == 0:
            print str(s) + '/' + str(sum_queue)

#定义一个run函数
def run(not_noly_list, func, need_dict):
    queue = Queue()
    for i in range(len(not_noly_list)):
        queue.put(not_noly_list[i])
    sum_queue = queue.qsize()
    for i in range(DEFAULT_THREAD_NUM):
        t = threading.Thread(target = work, args = (queue, func, need_dict, sum_queue))
        t.daemon = True
        t.start()
    
    while queue.unfinished_tasks > 0:
        time.sleep(1)
    
    queue.join()

def main():

    i = 0
    j = 0
    n = 0
    wheather_dir_exists(target_dir)
    dict2 = {}
    dict3 = {}
    list1 = []

    dict2 = generate_dict()
    open_pic_list = open('pic.list', 'r')
    for line in open_pic_list.readlines():
        n += 1
        if n%10000 == 0:
            print n
        line_split = line.split('/')
        get_name = line_split[-1][:-5]
        dict3[get_name] = line.strip('\n')

    for value in dict2.values():
        j += 1
        if len(value) > 1:**加粗样式**
            list1.append(value)

    func = generate_copy_func()
    run(list1, func, dict3)

main()

处理逻辑如下:

首先执行main()函数,其中:

**func = generate_copy_func()**调用 generate_copy_func()得到func
**run(list1, func, dict3)**调用run函数,将func和图片list以及字典dict传入run函数

其次,执行run()函数,其中:

queue = Queue() #调用Python中Queue生成一个对象object(我理解Queue应该是Python的一个类)
queue.pu #将图片list每一行扔到queue队列中(先进先出)
for i in range(DEFAULT_THREAD_NUM) #创建线程:threading.Thread(target=function_name, args=(function_parameter1, function_parameterN)) ,如上述代码:t = threading.Thread(target = work, args = (queue, func, need_dict, sum_queue)),每个线程都是调用函数work(),写法是target=work,传入参数也就是work函数需要的参数
t.daemon = True #这个我没有怎么去研究,可能和守护进程设置有关,默认好像是False,感兴趣可以另外查阅
t.start() #启动线程

while queue.unfinished_tasks > 0 #当判断queue队列中还有内容未处理完成,会等待1s,直到queue中内容全部被处理完成
queue.join() #阻塞作用,直到work()函数中queue.task_done()发出信号,告知已经全部完成,才会结束阻塞,继续进行主程序

执行work()函数

在执行run()函数时,创建线程时候已经调用work()函数,执行work()函数时,首先从queue中一个个取内容,取出一个,queue队列中少一个,这也是用queue起到多线程的神奇之处,多个线程同时调用,但是queue队列是取一个少一个,所以不会重复取或者乱掉
传参到func,并执行func函数

至少在我看来(可能认知有限),work()函数、run()函数以及满足应用场景的函数func()是可以完成这种简单的多线程处理任务(观点仅供参考)

发布了37 篇原创文章 · 获赞 2 · 访问量 7635

猜你喜欢

转载自blog.csdn.net/bingozb/article/details/98226244