python基础篇【第十一篇】线程、进程、协程

一、线程 

上一篇已经大致介绍了什么是线程以及线程的作用、多线程和进程的关系大致的总结如下:

  • 线程是最小的执行单元,进程由至少一个线程组成;
  • 进程和线程的调度,完全有操作系统决定,程序不能决定什么时候执行和执行多久。
  • 一个应用程序可以有多进程、多线程
  • 默认是单进程、单线程
  • 单进程,多线程,在Python中不会性能提升,在Java和C#中可以提升
  • 多线程: IO操作密集,一般不会用到CPU,效率提升是可以的
  • 多进程:计算型操作密集, 需要占用CPU,因此性能不会有提升

概念说了很多下面来点实际,代码!

创建线程:

import threading
def f1(arg):
    print(arg)
t=threading.Thread(target=f1,args=(123,))
t.start()   

简单吧这就是创建一个线程,也可以继承线程,自己创建

class MyThread(threading.Thread):   #自己创建一个类,继承threading.Thread)
    def __init__(self,func,args):
        self.func=func
        self.args=args
        super(MyThread,self).__init__()   #执行Mythread父类的构造函数

    def run(self):   #然后自己定义一个run方法
        self.func(self.args)    #执行f2函数

def f2(arg):
    print(arg)

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

threading常用方法:

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

Thread

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

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

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(arg):
    time.sleep(5)
    print(arg)
t = threading.Thread(target=f1,args=(123,))
t.setDaemon(True)   #True 表示主线程不等此子线程,默认值为False,也就是主线程等待子线程
t.start()  #不代表当前线程会被立即执行
t.join(6)  #表示主线程到此,等待。。
            # 参数6,表示主线程在此最多等待6秒

print(33)

线程锁

lock

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

为了避免资源争夺,所以引入了锁的概念。每当一个线程要访问共享数据时,必须先加把锁,而后在处理,处理完成后,解锁,让其他线程再来处理。

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

实例方法:

  • acquire([timeout])  上锁, 使线程进入同步阻塞状态,尝试获得锁定。
  • release()    释放锁,使用前线程必须已经获得锁定,否则抛出异常。
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()

#显示结果有可能会是 10个 0   其实我们想要的结果是 9 8 7......0   这就是产生了垃圾数据

那么我们来看看 上了锁之后会是神马效果:

NUM=10
def f1(l):
    global NUM
    l.acquire()    #上锁
    NUM-=1
    time.sleep(1)
    print(NUM)
    l.release()    #解锁

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

#这样就能我们想要的结果了

RLOCK

RLock() 是一个可以被同一个线程请求多次的同步指令。Rlock使用了“拥有的线程" 和 "递归等级"的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire() , 释放锁时需要调用release()相同次数。说白了就是LOCK只能锁住一次,RLOCK可多次锁定递归

可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用acquire()和release(),计数器将+1/-1,为0时处于未锁定状态。

NUM=10

def func(l):

    global NUM
    l.acquire()  #上锁
    NUM-=1
    l.acquire()  #上锁
    time.sleep(1)
    l.release()  #解锁
    print(NUM)

    l.release()  #解锁
# lock=threading.Lock() #只能锁一次

lock=threading.RLock() #锁多次
for i in range(10):
    t=threading.Thread(target=func,args=(lock,))
    t.start()

Semaphore(信号量)

Lock和Rlock(互斥锁),发现同时只能允许一个线程来更改数据,执行顺序不还是串行的么,所谓的多线程就没有神马卵用了。而Semaphore是同时允许一定数量的线程来更改数据。可以理解成互斥锁的加强版,一个锁可以控制多个thread的访问,Lock的话,只能让一个线程来访问,Semaphore可以控制数量。

#指定放行几个
NUM=10

def func(l,i):

    global NUM
    l.acquire()  #上锁
    NUM-=1
    time.sleep(2)
    print(NUM,i)
    l.release()  #解锁

lock=threading.BoundedSemaphore(5)  #锁5个线程
for i in range(15):
    t=threading.Thread(target=func,args=(lock,i))
    t.start()

#显示的结果
5 0
5 3
5 2
5 1
1 4
0 5
0 8
0 6
0 7
-4 9
-5 13
-5 10
-5 11
-5 12
-5 14
时间: 2024-10-27 06:52:37

python基础篇【第十一篇】线程、进程、协程的相关文章

Python的线程&进程&协程[0] -> 基本概念

基本概念 / Basic Concept 0 简介与动机 / Why Multi-Thread/Multi-Process/Coroutine 在多线程(multithreaded, MT)编程出现之前,计算机程序的执行是由单个步骤序列组成的,该序列在主机的CPU中按照同步顺序执行.即无论任务多少,是否包含子任务,都要按照顺序方式进行. 然而,假定子任务之间相互独立,没有因果关系,若能使这些独立的任务同时运行,则这种并行处理方式可以显著提高整个任务的性能,这便是多线程编程. 而对于Python而

15.python并发编程(线程--进程--协程)

一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完成(2)数据集:是程序在执行过程中所需要使用的一切资源(3)进程控制块:用来记录进程外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志.3.进程的作用:是想完成多任务并发,进程之间的内存地址是相互独立的二.线程:1.定义:最小的执行单位,线程的出现是为了

python学习笔记-(十四)进程&协程

一. 进程 1. 多进程multiprocessing multiprocessing包是Python中的多进程管理包,是一个跨平台版本的多进程模块.与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程.该进程可以运行在Python程序内部编写的函数.该Process对象与Thread对象的用法类似. 创建一个Process实例,可用start()方法启动. join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步.

线程 进程 协程

一.什么是线程? 线程是操作系统能够进行运算调度的最小单位(程序执行流的最小单元).它被包含在进程之中,是进程中的实际运作单位.一条线程指的是一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成.另外,线程是进程的中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源.一个线程可以创建和撤销另一

11 线程进程协程

1 线程 1.1 基本应用 1.1.1 标准线程(常用) import threading def f1(arg): print(arg) t = threading.Thread(target=f1, args=(123,)) t.start() 1.1.2 自定义线程 自定义线程类既threading.Thread流程,自定义run方法 import threading class MyThread(threading.Thread): #自定义类,继承threading.Thread类 d

Python的线程&进程&协程[0] -> 线程 -> 多线程锁的使用

锁与信号量 目录 添加线程锁 锁的本质 互斥锁与可重入锁 死锁的产生 锁的上下文管理 信号量与有界信号量 1 添加线程锁 由于多线程对资源的抢占顺序不同,可能会产生冲突,通过添加线程锁来对共有资源进行控制. 1 import atexit 2 from random import randrange 3 from threading import Thread, Lock, current_thread # or currentThread 4 from time import ctime, s

Python的线程&进程&协程[0] -> 线程 -> 多线程的建立与使用

常用的多线程功能实现 目录 生成线程的三种方法 单线程与多线程对比 守护线程的设置 1 生成线程的三种方法 三种方式分别为: 创建一个Thread实例,传给它一个函数 创建一个Thread实例,传给它一个可调用的类实例 派生Thread的子类,并创建子类的实例 # There are three ways to create a thread # The first is create a thread instance, and pass a function # The second one

Python的线程&进程&协程[1] -> 线程 -> 多线程的控制方式

多线程的控制方式 目录 唤醒单个线程等待 唤醒多个线程等待 条件函数等待 事件触发标志 函数延迟启动 设置线程障碍 1 唤醒单个线程等待 Condition类相当于一把高级的锁,可以进行一些复杂的线程同步控制.一般Condition内部都有一把内置的锁对象(默认为RLock),对于Condition的使用主要有以下步骤: 建立两个线程对象,及Condition对象; 线程1首先获取Condition的锁权限,acquire(); 线程1执行需要完成的任务后,调用等待wait(),此时,线程1会阻

Python的线程&进程&协程[2] -> 进程 -> 多进程的基本使用

多进程的基本使用 1 subprocess 常用函数示例 首先定义一个子进程调用的程序,用于打印一个输出语句,并获取命令行参数 1 import sys 2 print('Called_Function.py called, Hello world.') 3 try: 4 print('Got para', sys.argv[1:]) 5 except: 6 pass 再定义主函数,即父进程,分别测试 run() / call() / check_call() / getstatusoutput

第九天 线程 进程 协程 队列

详细链接http://www.cnblogs.com/alex3714/articles/5230609.html 1.线程:包含在进程中,是操作系统运算调度的最小单位,是一串指令的集合,直接与cpu交互 2进程:进程是一个程序各种资源的集合.操作系统通过管理这个集合进而运行程序,进程本身并不执行,进程通过调用线程来调度cpu. 3.不同点: 一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程 创建新线程很简单,但是创建一个子进程需要对父进程进行拷贝 线程共享内存,进程的内存是独