【问题标题】:How can I change multithreading with multiprocessing in the code (Python)如何在代码中使用多处理更改多线程(Python)
【发布时间】:2016-11-30 15:42:23
【问题描述】:

我编写了一个程序,它用线程和 python 队列实现凯撒密码。我想在我的代码中使用多处理更改所有线程工作,但我不知道该怎么做。如果您能解释在哪里以及如何开始实施,我将不胜感激。代码如下:

import threading
import Queue
import sys
import string

lock = threading.Lock()
def do_work(in_queue, out_queue, shift):
    while True:
        lock.acquire()
        item = in_queue.get()
        result = caesar(item, shift)
        out_queue.put(result)
        in_queue.task_done()
        lock.release()
def caesar(plaintext, shift):
    plaintext = plaintext.upper()
    alphabet = string.ascii_uppercase
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    table = string.maketrans(alphabet, shifted_alphabet)
    return plaintext.translate(table)

if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Duzgun giriniz: '<filename>.py s n l'")
        sys.exit(0)
    else:
        s = int(sys.argv[1])
        n = int(sys.argv[2])
        l = int(sys.argv[3])

    work = Queue.Queue()
    results = Queue.Queue()
    myfile=open('metin.txt','r')
    text_data=myfile.read() # <=== here load file
    index=0

    for i in xrange(n):
        t = threading.Thread(target=do_work, args=(work, results, s))
        t.daemon = True
        t.start()

    for i in range(0, len(text_data), l):
        work.put(text_data[index:index + l])
        index += l

    work.join()

    index=0
    output_file=open("crypted"+ "_"+ str(s)+"_"+str(n)+"_"+str(l)+".txt", "w")
    for i in range(0, len(text_data), l):
        output_file.write(results.get())
        index += l
    sys.exit()

【问题讨论】:

  • do_work 中的锁定有问题。但无论如何它不应该在那里。 Queue.get 已经是线程安全的,所以你没有保护它。相反,您的所有线程都在等待该锁,而 1 个线程完成工作。您已经有效地单线程了您的多线程应用程序。
  • 您可以用multiprocessing.Pool 池替换大部分代码并使用它的map 方法。作为一个额外的好处,multiprocessing.pool.ThreadPool 实现了具有相同接口的线程版本。

标签: python python-multithreading python-multiprocessing caesar-cipher


【解决方案1】:

您可以为自己节省一些代码并转到标准的multiprocessing.Pool 实现。

import multiprocessing
import sys
import string
import itertools

# for non-forking systems like Windows
def worker(args):
    # args: (text, shift)
    return caesar(*args)

# for forking systems like linux
def forking_worker(args):
    # args: ((start_index, end_index), shift)
    return caesar(text_data[args[0][0]:args[0][1], args[1])

def caesar(plaintext, shift):
    plaintext = plaintext.upper()
    alphabet = string.ascii_uppercase
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    table = string.maketrans(alphabet, shifted_alphabet)
    return plaintext.translate(table)

if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Duzgun giriniz: '<filename>.py s n l'")
        sys.exit(0)
    else:
        s = int(sys.argv[1])
        n = int(sys.argv[2])
        l = int(sys.argv[3])

    pool = multiprocessing.Pool() # todo: change number of cpus...
    with open('metin.txt') as myfile:
        text_data=myfile.read() # <=== here load file

    # on a forking system so only pass index, not text to child
    result = pool.map(forking_worker, 
        zip(((index, index + l)
            for index in range(0, len(text_data), l)),
            itertools.cycle([s])))

    with open("crypted"+ "_"+ str(s)+"_"+str(n)+"_"+str(l)+".txt", "w") as output_file:
        output_file.writelines(result)

【讨论】:

  • 非常感谢您的回答,即使我想使用分叉来实现这种多处理,这似乎效果更好。您对如何开始学习池函数有什么建议吗?
  • docs.python.org/3.6/library/multiprocessing.html 的标准文档是一个好的开始。但是在此过程中存在一些问题,因此对特定方法进行额外的谷歌搜索是个好主意。例如,在我给您的示例中,由于您使用的是分叉操作系统,因此您不需要将文本发送给孩子。我将改为使用索引进行更新。
猜你喜欢
  • 2016-11-16
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 2013-04-03
  • 1970-01-01
  • 2019-10-15
  • 2018-02-26
  • 2021-09-26
相关资源
最近更新 更多