个人比较习惯这种写法
举个简单的场景:
有一批图片和图片对应的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()是可以完成这种简单的多线程处理任务(观点仅供参考)