码迷,mamicode.com
首页 > 编程语言 > 详细

【Python之路Day11】网络篇之线程、进程、协程

时间:2016-07-18 18:38:51      阅读:277      评论:0      收藏:0      [点我收藏+]

标签:

目录:

基本概念

线程

进程

协程

 

 一. 基本概念

现在的操作系统,如Unix、Linux、Windows、Mac OS X等,都是支持“多任务”的操作系统。

什么叫”多任务“呢?简单理解,就是我们可以一般上网浏览某车之家的网页,看看喜欢的车型信息;一边打开某易云音乐听听好歌;一边打开某软件股市行情图,不安的盯着曲线图...卧槽,又尼玛跌了!  这就是多任务喽。

技术分享

多核心的CPU已经很普及了,但是,就是在过去的单核心CPU上,也可以执行多任务。

PS: CPU是分时间片的,假设任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3, 执行0.01秒....在这个切换的过程中,需要不断的保存程序的执行状态,和恢复执行状态,简单的说,这个过程就叫做”上下文切换", 注意,过多的上下文切换是会带来很多额外的开销的!

技术分享

对操作系统来说, 一个任务(程序)就是一个进程(Process), 比如打开浏览器访问某车之家,就是一个浏览器的进程。打开一个某易云音乐,就是一个某易云音乐进程(Process)。

这时候我忽然又想打开邮箱查收下邮件,然后在浏览器的标签栏里又打开了Gmail邮箱;然后我又想发条微博说下,卧槽,我在写博客!而后又打开浏览器的一个标签栏,打开了weibo.com... 也就是说在浏览器进程内部,我要同时做好些事情,这些子任务我们称为" 线程 ” (Thread).

每个进程至少要做一件事,所以,一个进程至少有一个线程,当然也可以有多个。多个线程可以同时运行,多线程的执行方式和多进程是一样的,也是由操作系统内核在多个线程(进程)之间快速切换,让每个线程(进程)都交替的运行,看起来就像是同时执行一样。当然,真正同时执行多线程需要多核心CPU才可能实现。

 Python既支持多进程,又支持多线程。

小结:

  • 线程是最小的执行单元,进程由至少一个线程组成;
  • 进程和线程的调度,完全有操作系统决定,程序不能决定什么时候执行和执行多久。
  • 多进程和多线程会会有资源同步和数据共享的问题。后面再续...  

多线程、多进程

  • 1. 一个应用程序可以有多进程、多线程
  • 2. 默认是单进程、单线程
  • 3. 单进程,多线程,在Python中不会性能提升,在Java和C#中可以提升。

提高并发:

  • 多线程: IO操作,一般不会用到CPU,效率提升是可以的
  • 多进程:计算型操作, 需要占用CPU,因此性能不会有提升

线程和进程是一个很重要的概念

一. 线程

1. 基础:

是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

概念太吓人了,先来看一下进程,这个相对于线程来说还是稍微好理解一点的。进程,是程序运行的实体,这句话的意思是,程序是存放在硬盘中的,当这个程序运行时,就会产生若干个进程,并且这个进程是可见的

那么什么是 线程呢,线程是一个任务流,它被包含在进程之中。

(1)线程的状态

线程有五种状态,状态转换如下图:

技术分享

(2) 线程同步(锁)

多线程的优势在于可以同时运行多个任务,而多个线程之间用到的数据可以共享进程的,效率很高(但在Python中多线程尽量应用在IO密集型的程序中)。正因为这样,所以存在数据不同步的问题.

为了避免资源争夺,所以引入了锁的概念。锁有两种状态:锁定和未锁定(这不废话么?)。每当一个线程要访问共享数据时,必须先加把锁,而后在处理,处理完成后,解锁,让其他线程再来处理。

线程与锁:

技术分享

 

(3) 线程通信(条件变量)

条件变量允许线程在条件不满足的时候等待,等到条件满足的时候的时候发出一个通知,而后继续运行。

 

 

技术分享

技术分享

(4) 线程运行和阻塞的状态转换

阻塞状态的三种情况:

  • 同步阻塞:运行竞争锁定的状态,线程请求锁定时将进入这个状态,一旦成功获得锁定又恢复到运行状态;
  • 等待阻塞:等待其他线程通知的状态,线程获得条件锁定后,调用“等待(wait())”将进入,一旦其他线程发出通知,线程将进入同步阻塞状态,再次竞争条件锁定;
  • 其他阻塞:运行的线程执行sleep()或者join()方法,或者发出I/O请求,会进入阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

2. 基本使用:

Python通过threading模块来提供对线程的支持。threading基于Java的线程设计模型。锁(Lock)和条件变量(condition)在Java中是对象的基本行为(每一个对象都自带了锁和条件变量),而Python中则是独立的对象。

Python Thread提供了Java Thread的行为的子集;

没有优先级、线程组,线程也不能被停止、暂停、恢复、中断。Java Thread中的部分被Python实现了的静态方法在Threading中以模块方法的形式提供。

threading常用方法:

threading.current_thread()   返回当前的线程变量。
threading.enumerate()         返回一个包含正在运行的线程的列表,正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.active_count()      返回正在运行的线程数量,与len(threading.enumerate())一样。

Thread

Thread是线程类,与Java类似,有两种使用方法,直接传入要运行的方法或从Thread继承并覆盖 run()。

PS: Thread中的run()方法,就是CPU来调度的时候执行的.

import threading
#创建线程第一种方法: 将要执行的方法做为参数传给方法
def f1(args):
    print(args)

t = threading.Thread(Target=f1, args=(123,))
t.start()
#第二种, 自定义一个类,而后继承threading.Thread
class MyThread(threading.Thread):  #自己写一个类,继承threading.Thread
    def __init__(self,func,args):
        self.func = func
        self.args = args
        super(MyThread, self).__init__()   #执行父类的构造方法

    def run(self):    #而后重写run方法
        self.func(self.args)

def f2(args):
    print(args)

res = MyThread(f2,456)   #传参数进去
res.start()              #开始线程

Thread构造方法(__init__):

  group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None

  • group: 线程组
  • target: 要执行的方法
  • name: 线程名
  • args/kwargs: 要传入的参数

常用方法:

  • is_alive():  返回线程是否在运行(启动前、终止前) 。
  • getName(): 获取当前线程名
  • setName():   设置线程名
  • isDaemon():  获取线程是否是守护线程。
  • setDaemon(): 设置是否是守护进程
    • 如果是后台线程,主线程执行过程中,后台线程也在运行,主线程执行完毕后,后台线程不论成功与否,全部都停止。
    • 如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程夜之星完成后,程序停止
  • start()  :  启动线程
  • join([timeout]):   阻塞当前上下文,直到调用此方法的线程终止或到达指定的timeout值
import threading
import time

def f1(args):
    time.sleep(5)
    print(args)

for i in range(10):
    t1 = threading.Thread(target=f1,args=(123,))
    t1.setDaemon(True)  #默认值为False,也就是主线程等待子线程,值为True之后,会不等子线程,直接往下解释执行,该退出就退出
    t1.start()
    t1.join(2)   #主线程阻塞,等待子线程等待完成, 参数的意思是最多等待的秒数. 如果不join的话,程序输出直接就是一个end,也就是子线程根本不会运行


print(End)

3. 线程锁

Lock

由于线程之间是进行随机调度的,每个线程可能只执行n条之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以线程锁就应用而生了。

Lock(指令锁) 是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。

Lock有两种状态: 

  • 锁定
  • 非锁定

以及两个基本的方法。

常用方法:

  • acquire([timeout])   使线程进入同步阻塞状态,尝试获得锁定。
  • release()    释放锁,使用前线程必须已经获得锁定,否则抛出异常。
#未使用锁的实例
import threading

NUM = 10
def f1(args):
    global NUM
    NUM -= 1
    print(NUM)

for i in range(10):
    t = threading.Thread(target=f1,args=(i,))
    t.start()
#使用Lock实例
import threading,time

NUM = 10

lock = threading.Lock()

def f1(args):
    global NUM
    lock.acquire()    #加锁
    NUM -= 1
    time.sleep(1)
    print(NUM)
    lock.release()    #释放锁

for i in range(10):
    t = threading.Thread(target=f1,args=(i,))
    t.start()

 

二. 进程

1. 概念:

是计算机中已运行程序的实体。进程为曾经是分时系统的基本运作单位。在面向进程设计的系统(如早期的UNIX,Linux 2.4及更早的版本)中,进程是程序的基本执行实体;在面向线程设计的系统(如当代多数操作系统、Linux 2.6及更新的版本)中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。  

 

 

三. 协程

 

【Python之路Day11】网络篇之线程、进程、协程

标签:

原文地址:http://www.cnblogs.com/dubq/p/5680489.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!