线程池和进程池

池的概念

由于服务器的硬件资源“充裕”,那么提高服务器性能的一个很直接的方法就是以空间换时间,即“浪费”服务器的硬件资源,以换取其运行效率。这就是池的概念。
池是一组资源的集合,这组资源在服务器启动之初就完全被创建并初始化,这称为静态资源分配

当服务器进入正式运行阶段,即开始处理客户请求的时候,如果它需要相关的资源,就可以直接从池中获取,无需动态分配。很显然,直接从池中取得所需资源比动态分配资源的速度要快得多,因为分配系统资源的系统调用都是很耗时的当服务器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用来释放资源

从最终效果来看,池相当于服务器管理系统资源的应用设施,它避免了服务器对内核的频繁访问。

池可以分为多种,常见的有内存池进程池线程池连接池

执行多个任务怎么办?
一种是启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。

还有一种方法是启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。

同时执行多个任务通常各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务1必须暂停等待任务2完成后才能继续执行,有时,任务3和任务4又不能同时执行,多进程和多线程的程序的复杂度要远远高于单进程单线程的程序。

线程是最小的执行单元,而进程由至少一个线程组成。

如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间。

多线程

一个进程内可以有多个线程(至少一个主线程),多个线程共享该进程的所有变量同时对全局变量进行访问和改写很容易出现混乱,所以需要用锁进行线程的同步控制(信号量,互斥锁)

import time, threading

def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n = n+1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s is end.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s is end.' % threading.current_thread().name)

多线程和多进程的实现很类似,进程启动时默认的线程为主线程,主线程之外可以开启新的子线程,current_thread()函数返回当前线程的实例

多进程

Linux/Unix操作系统提供了fork()系统调用,fork执行一次会返回两次,分别在父进程和子进程内返回(先父进程再子进程),父进程返回的是子进程的ID子进程返回0。父进程要记下所有子进程的ID,而子进程可以通过getppid()获得父进的ID

from multiprocessing import Process
import os

def run_proc(name):
    print 'Run child process %s (%s)' % (name, os.getpid())

if __name__ == '__main__':
    print 'Parent process %s.' % os.getpid()
    p1 = Process(target=run_proc, args=('test1',))
    p2 = Process(target=run_proc, args=('test2',))
    p3 = Process(target=run_proc, args=('test3',))
    p4 = Process(target=run_proc, args=('test4',))
    print 'Process will start.'
    p1.start()
    p2.start()
    p3.start()
    p4.start()
    p1.join()
    p2.join()
    p3.join()
    p4.join()

进程池和线程池

关键性作用:用户如果想创建新的进程,可以直接取得资源,从而避免了动态分配资源(这是很耗时的)
预先创建一组子进程,当有新任务来时,系统通过 调配 该组进程中的某个 子进程 完成此任务。

进程池是由服务器预先创建的一组子进程,这些子进程的数目在 3~10 个之间(当然这只是典型情况)。线程池中的线程数量应该和 CPU 数量差不多。
所有子进程都运行着相同的代码,并具有相同的属性,比如优先级、 PGID 等
当有新的任务来到时,主进程将通过某种方式选择进程池中的某一个子进程来为之服务

最后用代码实现一下进程池:

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print 'Run task %s (%s)...' % (name, os.getpid())
    start = time.time()
    time.sleep(random.random()*3)
    end = time.time()
    print 'Task %s runs %0.2f seconds.' % (name, end-start)

if __name__ == '__main__':
    print 'Parent process %s.' % os.getpid()
    p = Pool()
    for i in range(5):
        p.apply_async(long_time_task, (i,))
    print 'Waiting for all subprocesses done...'
    p.close()
    p.join()
    print 'All subprocesses done.'

线程池主要用于:

1)需要大量的线程来完成任务,且完成任务的时间比较短
比如WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大。但对于长时间的任务,
比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。

2)对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

3)接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用

并发:实质 是 一个核物理cpu (或多核)在若干程序之间 多路复用,并发性是多事件对有限物理资源 强行共享提高效率.
互斥:既一个公共资源同时只能被一个进程或一个线程使用。
并行:指两个及以上的事件在同一时刻发生。可以使 多个程序 同时 在不同的cpu 上同时执行。多个实体,多个事件,同时发生。
异步:是指进程 不需要 一直等 而是继续执行 下面的操作,不管其他进程的状态,当有消息返回时,系统会通知进程进行处理。
阻塞:资源被占用 死等。厕所 被占 ,等着 里面的人出来。当调用某个方法,当前的执行流程 会被挂起;只有当这个函数返回结果,才会被继续执行。
非阻塞:资源被占用 不等待 做其他事情。厕所 被占了 ,去吃饭。调用某个方法时,这个方法没有立刻返回 ,当前的 流程 不会被 挂起,继续执行自己的指令。
同步:它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是:两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。
顺序执行 就是 就是并发,你一个人干可以多件事,时间是顺序执行
同时 执行两个步骤 ,那就是 并行处理 ,那么这两个事件 ,也是 异步

你可能感兴趣的:(线程池和进程池)