python中进程和线程

为什么要用进程和线程

多线程是编程过程中经常会使用到的手段,其目的是为了能提高任务执行的效率,很多时候系统都需要创建多个进程以提高CPU的利用率,当数量较少时,可以手动生成一个个Process实例。当进程数量很多时,或许可以利用循环,但是这需要程序员手动管理系统中并发进程的数量,有时会很麻烦。虽然Python多线程有缺陷,总被人说成是鸡肋,但也不是一无用处,它很适合用在IO密集型任务中。I/O密集型执行期间大部分是时间都用在I/O上,如数据库I/O,较少时间用在CPU计算上。因此该应用场景可以使用Python多线程,当一个任务阻塞在IO操作上时,我们可以立即切换执行其他线程上执行其他IO操作请求。

process 进程

1、process概念:进程是由一段代码程序组成的应用程序,其在运行时操作系统会分配给该进程独立的系统资源(内存)

2、多进程的运行:在操作系统中,通常采用“时间片轮转法”的策略,来实现应用程序(进程)的并行。当一个应用程序在操作系统中运行时,操作系统会自动给该进程分配一个ID,用来唯一标识该进程

import os
from multiprocessing import Process

def run_proc(name):
    print('运行的子程序(%s)' %os.getpid())

if __name__ == '__main__':
    print('父进程的进程ID(%s)' % os.getpid())
    p = Process(target=run_proc,args=('test',))
    print('子进程开始运行')
    p.start()
    p.join()
    print('子进程结束')


Thread

3、线程的概念:线程是不能够独立存在于操作系统中,需要依赖于进程的存在。在python中,一个进程至少有一个主线程(mainthread)。多进程和多线程都可以执行多个任务,线程是进程的一部分。线程的特点是线程之间可以共享内存和变量,资源消耗少(不过在Unix环境中,多进程和多线程资源调度消耗差距不明显,Unix调度较快),缺点是线程之间的同步和加锁比较麻烦。那么多个线程同时共享同一个进程的资源。

4、线程的实现:

在python中线程的实现,根据不同的操作系统来区分:

1)Linux/Unix/Mac:python 通过调用os模块中的fork()函数,进行创建子进程。

2)windows:python通过调用multiprocessing模块,来实现。

3)进程的运行:在oython程序中,我们通过实例化一个Process进程对象,

代码如下:

p = Process(target=run_proc,args=('test',))其中,target用来指定进程的功能,args指定进程的名称等内容。

注意:此时进程已经具备了可以运行的相关软件,但还未运行。在调用了start()函数后,该进程开始运行,如果遇到join()函数,表示该进程会被挂起(等待)

直到其他子进程执行完毕后,再执行自身未完成的内容。

当进程执行完毕后,或出现异常时,进程即结束。不需要我们进行人工干预。

import threading
import time
 
def target():
    print 'the curent threading  %s is running' % threading.current_thread().name
    time.sleep(1)
    print 'the curent threading  %s is ended' % threading.current_thread().name
 
print 'the curent threading  %s is running' % threading.current_thread().name
t = threading.Thread(target=target)
 
t.start()
t.join()
print 'the curent threading  %s is ended' % threading.current_thread().name
 
输出:
the curent threading  MainThread is running
the curent threading  Thread-1 is running
the curent threading  Thread-1 is ended
the curent threading  MainThread is ended

start是启动线程,join是阻塞当前线程,即使得在当前线程结束时,不会退出。从结果可以看到,主线程直到Thread-1结束之后才结束。
Python中,默认情况下,如果不加join语句,那么主线程不会等到当前线程结束才结束,但却不会立即杀死该线程。如不加join输出如下:

the curent threading  MainThread is running
the curent threading  Thread-1 is running
 the curent threading  MainThread is ended
the curent threading  Thread-1 is ended

但如果为线程实例添加t.setDaemon(True)之后,如果不加join语句,那么当主线程结束之后,会杀死子线程。代码:

import threading
import time
def target():
    print 'the curent threading  %s is running' % threading.current_thread().name
    time.sleep(4)
    print 'the curent threading  %s is ended' % threading.current_thread().name
print 'the curent threading  %s is running' % threading.current_thread().name
t = threading.Thread(target=target)
t.setDaemon(True)
t.start()
t.join()
print 'the curent threading  %s is ended' % threading.current_thread().name
输出如下:
the curent threading  MainThread is running
the curent threading  Thread-1 is runningthe curent threading  MainThread is ended


如果加上join,并设置等待时间,就会等待线程一段时间再退出:

import threading
import time
def target():
    print 'the curent threading  %s is running' % threading.current_thread().name
    time.sleep(4)
    print 'the curent threading  %s is ended' % threading.current_thread().name
print 'the curent threading  %s is running' % threading.current_thread().name
t = threading.Thread(target=target)
t.setDaemon(True)
t.start()
t.join(1)
输出:
the curent threading  MainThread is running
the curent threading  Thread-1 is running
the curent threading  MainThread is ended


主线程等待1秒,就自动结束,并杀死子线程。如果join不加等待时间,t.join(),就会一直等待,一直到子线程结束,输出如下:

the curent threading  MainThread is running
the curent threading  Thread-1 is running
the curent threading  Thread-1 is ended
the curent threading  MainThread is ended

5、线程的运行机制:

1)首先,python虚拟机,设置GIL(全局解释锁)。供调用相关资源的线程使用。

2)然后,调用相关的线程,该线程会获得锁的持有权,对需要调用的资源进行上锁。

3)进行相关代码功能的执行后,主动让出锁的控制权,比如:sleep

4)线程进入休眠状态

5)切换下一个线程,继续重复上述步骤。

 

生产者-消费者问题:
1、简单实现

import threading
import time
product = None #社会商品
condition = threading.Condition()#条件变量,用来判断是否继续生产或消费


def producer():#生产者
    global product
    if condition.acquire():#判断是否获的了锁
        while True:
            if product is None:
                print('生产中。。。。。')
                product = 'anything'
                condition.notify() #通知消费者,商品已经生产完毕
            condition.wait()#等待消费者的生产通知
            time.sleep(2)


def consumer():#消费者
    global product
    if condition.acquire():#判断是否获的了锁
        while True:
            if product is not None:
                print('消费中.....')
                product = None
                condition.notify()#通知生产者,已经消费完毕
            condition.wait()#等待生产者的消费通知
            time.sleep(2)


t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)
t2.start()
t1.start()

 

结果:

父进程的进程ID(6548)
子进程开始运行
运行的子程序(6440)
子进程结束

 

在Python中,有一个GIL,即全局解释锁,该锁的存在保证在同一个时间只能有一个线程执行任务,也就是多线程并不是真正的并发,只是交替得执行。

GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操作cpu,只能利用GIL保证同一时间只能有一个线程拿到数据。而在pypython和jpython中是没有GIL的。

虽然Python的多线程多被诟病但是Python多线程在IO密集型任务中还是很有用处的,而对于计算密集型任务,应该使用Python多进程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值