1. 程式人生 > >python多執行緒帶返回值案例

python多執行緒帶返回值案例

問題場景

業務需要對網頁進行PDF轉換,用到了python的pdfkit模組。因報告是成批下來,每批幾百例需要轉換,為了加快報告生成效率,python裡採用了多執行緒寫法。筆者語言是java,所以利用了**Runtime.getRuntime().exec(cmd)**進行呼叫。

環境:jdk8, python 2.7, idea

CODE

import threading
import ast
import pdfkit
import sys
import getopt
import codecs

class MyThread(threading.Thread):
    def __init__(self, func, args=()):
        super(MyThread, self).__init__()
        self.func = func
        self.args = args

    def run(self):
        self.result = self.func(*self.args)

    def get_result(self):
        try:
            return self.result
        except Exception:
            return None

def createpdf(url, path):
    options = {
        'margin-top': '0in',
        'margin-right': '0in',
        'margin-bottom': '0in',
        'margin-left': '0in',
        'encoding': "UTF-8",
        'javascript-delay': '60000',
    }
    num = 0
    compete = pdfkit.from_url(url, path, options=options)
    if compete:
        num = 1

    return num

if __name__ == '__main__':
    # Get the parameter list
    parameterList = sys.argv[1:]
    url = ''
    file_name = ''
    opts, args = getopt.getopt(parameterList, "u:f:", ['url=', 'file_name='])
    for opt, arg in opts:
        if opt in ("-u", "--url"):
            url = arg
        elif opt in ("-f", "--file_name"):
            file_name = arg

    # print('url:', url)
    # print('file_name:', file_name)

    # 引數太長,Process傳參有32K限制,故把引數寫到檔案裡再讀出來用,機智有木有
    sample_map = {}
    f = codecs.open(filename=file_name, mode="r+", encoding='utf-8')
    lines = f.readlines()
    sample_map_string = ''
    for line in lines:
        sample_map_string = line
        break

    sample_map = ast.literal_eval(sample_map_string)
    # print('sample_map:', sample_map)
    li = []
    for i in sample_map.keys():
        t = MyThread(createpdf, args=(url + '?sample_sn=%s' % i, sample_map.get(i)))
        li.append(t)
        t.start()

    compete_num = 0
    for t in li:
        t.join()
        compete_num = t.get_result() + compete_num

    print "completed:" + bytes(compete_num)

   /**
     * 批量生成報告
     * @param map
     * @param productMap
     * @param sampleList
     * @param storeDir
     * @param url
     * @param pyPre
     * @param uuid
     * @param storePrefix
     * @return
     */
    public static int createFor(Map<String, String> map, Map<String, String> productMap,
                                List<String> sampleList, String storeDir, String url, String pyPre, String uuid, String storePrefix) {
        String date = DateUtil.date2Str(new Date());
        StringBuilder pathTemp = new StringBuilder("");
        String companyId;
        String productCode;
        String cmd;
        int sum = 0;
        Map<String, String> sampleMap = new LinkedHashMap<>(sampleList.size());
        String paraFileName;
        try {
            String path;
            for (String sampleCode : sampleList) {
                companyId = map.get(sampleCode);
                productCode = productMap.get(sampleCode);
                pathTemp.append(storeDir).append(date).append("-").append(uuid).append(File.separator).append(companyId).append(File.separator).append(productCode);
                path = pathTemp.toString();
                pathTemp.setLength(0);
                File file = new File(path);
                if (!file.exists()) {
                    file.mkdirs();
                }
                path += File.separator + sampleCode + "-" + productCode + ".pdf";
                path = path.replace("\\", "/");
                sampleMap.put(sampleCode, path);
            }
            paraFileName = storePrefix + DateUtil.date2Str(new Date()) + "-" + EncryUtil.getUUID() + ".txt";
            boolean success = writeMapFile(sampleMap, paraFileName);
            if (success) {
                cmd = "python " + pyPre + "mul_result.py -u " + url + " -f " + paraFileName;
                Process pr = Runtime.getRuntime().exec(cmd);
                BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
                String result = null;
                String line;
                while ((line = in.readLine()) != null) {
                    result = line;
                    System.out.println(result);
                    log.info("creating: {}", result);
                }
                if (result != null && result.contains("completed:")) {
                    sum = Integer.parseInt(result.split(":")[1]);
                }
                in.close();
                pr.waitFor();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sum;
    }

   /**
     * map寫進檔案裡
     * // a = {'a':'hangge','b':'man','school':'wust'}
     * @param sampleMap
     * @param paraFileName
     * @return
     */
    public static boolean writeMapFile(Map<String, String> sampleMap, String paraFileName) {
        boolean res = false;
        BufferedWriter bw = null;
        try {
            File file = new File(paraFileName);
            if (!file.exists()) {
                CommonUtil.createFile(paraFileName);
            }
            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(paraFileName)));
            if (sampleMap.size() > 0) {
                bw.write('{');
                int index = 0;
                for (String key : sampleMap.keySet()) {
                    bw.write('\'');
                    bw.write(key);
                    bw.write('\'');
                    bw.write(':');
                    bw.write('\'');
                    bw.write(sampleMap.get(key));
                    bw.write('\'');
                    if (index < sampleMap.size() - 1) {
                        bw.write(',');
                    }
                    index++;
                }
                bw.write('}');
                res = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }try {
            if (bw != null) {
                bw.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }