Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
多处理与线程化Python_Python_Multithreading_Multiprocessing - Fatal编程技术网

多处理与线程化Python

多处理与线程化Python,python,multithreading,multiprocessing,Python,Multithreading,Multiprocessing,我正在努力理解“超过”的优点。我知道,多处理绕过了全局解释器锁,但是还有什么其他的优势,并且线程不能做同样的事情呢?关键的优势是隔离。进程崩溃不会导致其他进程崩溃,而线程崩溃可能会对其他线程造成严重破坏。线程化模块使用线程,多处理模块使用进程。不同之处在于线程在相同的内存空间中运行,而进程有单独的内存。这使得使用多处理的进程之间共享对象变得有点困难。由于线程使用相同的内存,因此必须采取预防措施,否则两个线程将同时写入同一内存。这就是全局解释器锁的作用 生成进程比生成线程慢一点。另一件没有提到的事

我正在努力理解“超过”的优点。我知道,多处理绕过了全局解释器锁,但是还有什么其他的优势,并且线程不能做同样的事情呢?

关键的优势是隔离。进程崩溃不会导致其他进程崩溃,而线程崩溃可能会对其他线程造成严重破坏。

线程化模块使用线程,
多处理模块使用进程。不同之处在于线程在相同的内存空间中运行,而进程有单独的内存。这使得使用多处理的进程之间共享对象变得有点困难。由于线程使用相同的内存,因此必须采取预防措施,否则两个线程将同时写入同一内存。这就是全局解释器锁的作用


生成进程比生成线程慢一点。

另一件没有提到的事情是,它取决于您使用的操作系统的速度。在Windows中,进程的成本很高,因此线程在Windows中会更好,但在unix中,进程比其Windows变体更快,因此在unix中使用进程更安全,而且生成速度更快。

线程的任务是使应用程序能够响应。假设您有一个数据库连接,并且需要响应用户输入。如果没有线程,如果数据库连接繁忙,应用程序将无法响应用户。通过将数据库连接拆分为单独的线程,可以使应用程序更具响应性。另外,由于两个线程处于同一进程中,因此它们可以访问相同的数据结构—良好的性能,加上灵活的软件设计

请注意,由于GIL,应用程序实际上并不是同时做两件事,但我们所做的是将数据库上的资源锁放在一个单独的线程中,以便CPU时间可以在它和用户交互之间切换。CPU时间在线程之间分配


多处理是指在给定的时间内,您确实希望完成多件事情的情况。假设您的应用程序需要连接到6个数据库,并对每个数据集执行复杂的矩阵转换。将每个作业放在一个单独的线程中可能会有所帮助,因为当一个连接空闲时,另一个连接可能会获得一些CPU时间,但处理不会并行进行,因为GIL意味着您只能使用一个CPU的资源。通过将每个作业放在一个多处理进程中,每个作业都可以在自己的CPU上运行并以最高效率运行。

以下是我提出的一些优点/缺点

多处理 赞成的意见
  • 独立存储空间
  • 代码通常很简单
  • 利用多个CPU和内核
  • 避免cPython的GIL限制
  • 消除了对同步原语的大部分需求,除非您使用共享内存(相反,它更像是IPC的通信模型)
  • 子进程是可中断/可终止的
  • Python
    多处理
    模块包含有用的抽象,其接口非常类似于
    threading.Thread
  • 必须使用cPython才能进行CPU绑定处理
欺骗
  • IPC稍微复杂一些,开销更大(通信模型与共享内存/对象)
  • 更大的内存占用
穿线 赞成的意见
  • 轻量级-低内存占用
  • 共享内存-使从另一个上下文访问状态更容易
  • 允许您轻松创建响应性UI
  • 正确释放GIL的cPython C扩展模块将并行运行
  • I/O绑定应用程序的最佳选择
欺骗
  • cPython-受GIL约束
  • 不可中断/可终止
  • 如果不遵循命令队列/消息泵模型(使用
    队列
    模块),则需要手动使用同步原语(需要决定锁定的粒度)
  • 代码通常更难理解,也更难正确理解-竞争条件的可能性急剧增加

其他答案更多地集中在多线程与多处理方面,但在python中,必须考虑全局解释器锁(GIL)。当创建更多的线程(比如k个)时,它们通常不会将性能提高k倍,因为它仍将作为单线程应用程序运行。GIL是一个全局锁,它锁定所有内容,只允许使用单个内核执行单线程。在使用诸如numpy、网络、I/O等C扩展的地方,性能确实有所提高,在这些地方,大量的后台工作已经完成,GIL已经发布
因此,当使用线程时,只有一个操作系统级线程,而python创建的伪线程完全由线程本身管理,但实际上是作为单个进程运行的。抢占发生在这些伪线程之间。如果CPU以最大容量运行,您可能希望切换到多处理。

现在,对于自包含的执行实例,您可以选择池。但在数据重叠的情况下,如果需要进程通信,则应使用
多处理。进程

进程可能有多个线程。这些线程可以共享内存,并且是进程中的执行单元


进程在CPU上运行,因此线程驻留在每个进程下。流程是独立运行的单个实体。如果要在每个进程之间共享数据或状态,可以使用内存存储工具,例如
缓存(redis,memcache)
文件
,或
数据库

,如问题中所述,Python中的多处理是实现真正并行性的唯一真正方法多线程无法
#!/usr/bin/env python3

import multiprocessing
import threading
import time
import sys

def cpu_func(result, niters):
    '''
    A useless CPU bound function.
    '''
    for i in range(niters):
        result = (result * result * i + 2 * result * i * i + 3) % 10000000
    return result

class CpuThread(threading.Thread):
    def __init__(self, niters):
        super().__init__()
        self.niters = niters
        self.result = 1
    def run(self):
        self.result = cpu_func(self.result, self.niters)

class CpuProcess(multiprocessing.Process):
    def __init__(self, niters):
        super().__init__()
        self.niters = niters
        self.result = 1
    def run(self):
        self.result = cpu_func(self.result, self.niters)

class IoThread(threading.Thread):
    def __init__(self, sleep):
        super().__init__()
        self.sleep = sleep
        self.result = self.sleep
    def run(self):
        time.sleep(self.sleep)

class IoProcess(multiprocessing.Process):
    def __init__(self, sleep):
        super().__init__()
        self.sleep = sleep
        self.result = self.sleep
    def run(self):
        time.sleep(self.sleep)

if __name__ == '__main__':
    cpu_n_iters = int(sys.argv[1])
    sleep = 1
    cpu_count = multiprocessing.cpu_count()
    input_params = [
        (CpuThread, cpu_n_iters),
        (CpuProcess, cpu_n_iters),
        (IoThread, sleep),
        (IoProcess, sleep),
    ]
    header = ['nthreads']
    for thread_class, _ in input_params:
        header.append(thread_class.__name__)
    print(' '.join(header))
    for nthreads in range(1, 2 * cpu_count):
        results = [nthreads]
        for thread_class, work_size in input_params:
            start_time = time.time()
            threads = []
            for i in range(nthreads):
                thread = thread_class(work_size)
                threads.append(thread)
                thread.start()
            for i, thread in enumerate(threads):
                thread.join()
            results.append(time.time() - start_time)
        print(' '.join('{:.6e}'.format(result) for result in results))
            +--------------------------------------+
            + Active threads / processes           +
+-----------+--------------------------------------+
|Thread   1 |********     ************             |
|         2 |        *****            *************|
+-----------+--------------------------------------+
|Process  1 |***  ************** ******  ****      |
|         2 |** **** ****** ** ********* **********|
+-----------+--------------------------------------+
            + Time -->                             +
            +--------------------------------------+
import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))
import concurrent.futures
import math

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))

if __name__ == '__main__':
    main()