python学习-线程、进程、协程

线程

python 的 threading 模块提供了线程的相关操作,线程是应用程序中工作的最小单元。

import time
import threading

def process(arg):
    time.sleep(1)
    print(arg)

if __name__ == ‘__main__‘:

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

通过 threading 模块实现多线程,本身需要至少 10s 的程序会很快执行完成

start()
    # 线程准备就绪,等待 CPU 的调度
setDaemon()
    # 为线程命名
getName()
    # 获取线程名称
setDaemon(True)
    # 设置是否为后台进程,默认为 False
    # 为 True 时,主线程执行时,后台线程也在执行,当主线程执行完成后,无论后台的子线程是否执行完成,都会被停止
    # 为 False 时,主线程为等待子线程执行完成后再中止
join()
    # 逐个执行线程,执行完毕后继续向下执行,该方法使多线程失去了意义
run()
    # 线程被 CPU 调度后自动执行线程对应的 run 方法

创建多线程的两种方法

import threading

def f1(x):
    print(x)

# 第一种方法:常用
t = threading.Thread(target=f1, args=(1,))
t.start() # t.start() 表示线程已经准备就绪,等待 CPU 调用, CPU 在调用的时候,其实就是调用 run() 方法

# 第二种方法:
class MyThread(threading.Thread):
    def __init__(self, func, args):
        self.func = func
        self.args = args
        super(MyThread, self).__init__()

    def run(self):
        self.func(self.args)

obj = MyThread(f1, 123)
obj.start()

线程锁(Lock,RLock)

threading 的 Lock 和 RLock 方法提供了线程锁的功能,同时只允许一个线程更改数据

Lock 方法不支持多重锁

RLock 方法支持多重锁,一般使用 RLock 方法

由于线程之间的数据是共享的,当多个线程同时修改一个数据时,就会出现脏数据,此时就需要通过线程锁来让线程一个一个修改数据

"""
创建一个全局变量 NUM = 10, 通过 func 函数每次自减 1,1s 后打印数据
"""

import time
import threading

NUM = 10

def func():
    # 修改全局变量
    global NUM
    NUM -= 1
    # 等待 1s 后输出 NUM
    time.sleep(1)
    print(NUM)

# 创建 10 个线程执行 func 函数
for i in range(10):
    t = threading.Thread(target=func)
    t.start()

################ 输出结果 ################
0
0
0
0
0
0
0
0
0
0

无线程锁时,输出的值全部都为 0,输出的结果是所有线程修改后的数据。

通过线程锁,使数据同时只能让一个线程修改

import time
import threading

NUM = 10

# 创建锁
lock = threading.RLock()

def func():
    # 上锁
    lock.acquire()

    # 修改全局变量
    global NUM
    NUM -= 1
    # 等待 1s 后输出 NUM
    time.sleep(1)
    print(NUM)

    # 解锁
    lock.release()

# 创建 10 个线程执行 func 函数
for i in range(10):
    t = threading.Thread(target=func)
    t.start()

################ 输出结果 ################
9
8
7
6
5
4
3
2
1
0

信号量(Semaphore)

同时允许多个线程

import time
import threading

semaphore = threading.Semaphore(2)

def func(x):
    semaphore.acquire()
    time.sleep(1)
    print(x)
    semaphore.release()

# 创建 10 个线程执行 func 函数
for i in range(10):
    t = threading.Thread(target=func, args=(i,))
    t.start()

事件(Event)

通过主线程控制子线程的执行,主要有三个方法 set,wait,clear

事件处理会在全局定义一个 Flag,如果 Flag 为 False,那么当执行到 event.wait 时就会阻塞,当 Flag 为 True 是,event.wait 就不会阻塞。和红绿灯机制相似

  • claer 将 Flag 设置为 False
  • set 将 Flag 设置为 True
  • wait 阻塞
import time
import threading

event = threading.Event()

def func(x):
    event.wait()
    time.sleep(1)
    print(x)
    event.wait()

# 创建 10 个线程执行 func 函数
for i in range(10):
    t = threading.Thread(target=func, args=(i,))
    t.start()

# Flag 默认为 False
inp = input(‘>‘)
if inp:
    event.set()

条件(Condition)

线程默认等待,只有满足某个条件时,才会释放 n 个线程

import threading

condition = threading.Condition()

def func(x):
    condition.acquire()
    condition.wait()
    print(x)
    condition.release()

# 创建 10 个线程执行 func 函数
for i in range(10):
    t = threading.Thread(target=func, args=(i,))
    t.start()

while True:
    inp = input(‘>‘)
    if inp:
        condition.acquire()
        # 释放 int(inp) 个线程
        condition.notify(int(inp))
        condition.release()

定时器(Timer)

指定 n 秒后执行某操作

import threading

def func():
    print("Hello World")

t = threading.Timer(1, func)
t.start()

进程

创建子进程需要使用 multiprocess 模块

from multiprocessing import Process

def f():
    print("Hello")

for i in range(2):
    p = Process(target=f,)
    p.start()

进程间数据共享

进程间默认无数据共享,

import time
from multiprocessing import Process

li = []

def f(x):
    li.append(x)
    time.sleep(1)
    # 输出各自的结果
    print(li)

for i in range(10):
    p = Process(target=f, args=(i,))
    p.start()

创建 Array 时必须指定类型

‘c‘: ctypes.c_char,  ‘u‘: ctypes.c_wchar,
‘b‘: ctypes.c_byte,  ‘B‘: ctypes.c_ubyte,
‘h‘: ctypes.c_short, ‘H‘: ctypes.c_ushort,
‘i‘: ctypes.c_int,   ‘I‘: ctypes.c_uint,
‘l‘: ctypes.c_long,  ‘L‘: ctypes.c_ulong,
‘f‘: ctypes.c_float, ‘d‘: ctypes.c_double

通过Array实现进程间数据共享

通过Manager实现进程间数据共享

from multiprocessing import Process, Queue

def f():

    print(q.get())

if __name__ == ‘__main__‘:
    q = Queue()
    q.put(1)
    q.put(2)
    q.put(3)
    q.put(4)

    for i in range(4):
        p = Process(target=f)
        p.start()

通过Queue实现进程间数据共享

进程池

from multiprocessing import Process, Pool

def f(x):
    time.sleep(2)
    print(x)

pool = Pool(5)
for i in range(10):
    pool.apply_async(f,args=(i,))

print(‘end‘)
pool.close()
pool.join()

协程

线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;

from greenlet import greenlet

def func1():
    print("func1 11")
    gr2.switch()
    print("func1 22")
    gr2.switch()

def func2():
    print("func2 11")
    gr1.switch()
    print("func2 22")

if __name__ == ‘__main__‘:
    gr1 = greenlet(func1)
    gr2 = greenlet(func2)
    gr1.switch()

通过greenlet实现

import gevent

def func1():
    print("func1 11")
    gevent.sleep()
    print("func1 22")

def func2():
    print("func2 11")
    gevent.sleep()
    print("func2 22")

if __name__ == ‘__main__‘:
    gevent.joinall([
        gevent.spawn(func1),
        gevent.spawn(func2),
    ])

通过gevent实现

请求 URL 实例:

from gevent import monkey
import gevent
import requests

monkey.patch_all()

def geturl(url):
    print("GET: %s" % url)

    resp = requests.get(url)
    data = resp.text
    print("%s types received from %s" % (len(data), url))

gevent.joinall([
    gevent.spawn(geturl, ‘https://www.baidu.com‘),
    gevent.spawn(geturl, ‘https://www.python.org‘),
    gevent.spawn(geturl, ‘https://github.com‘),
])

用途

多线程:用于 IO 密集型操作

多进程:用于计算密集型操作

协程:用于线程内部,解决 IO 等待

时间: 2024-10-05 19:50:21

python学习-线程、进程、协程的相关文章

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

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

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的线程&进程&协程[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的线程&进程&协程[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

python简单线程和协程学习

python中对线程的支持的确不够,不过据说python有足够完备的异步网络框架模块,希望日后能学习到,这里就简单的对python中的线程做个总结 threading库可用来在单独的线程中执行任意的python可调用对象.尽管此模块对线程相关操作的支持不够,但是我们还是能够用简单的线程来处理I/O操作,以减低程序响应时间. from threading import Thread import time def countdown(n): while n > 0: print('T-minus:

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

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

python学习道路(day11note)(协程,同步与异步的性能区别,url爬网页,select,RabbitMq)

1.协程 1 #协程 又称微线程 是一种用户的轻量级线程 程序级别代码控制 就不用加机器 2 #不同函数 = 不同任务 A函数切到B函数没有进行cpu级别的切换,而是程序级别的切换就是协程 yelied 3 4 #单线程下多个任务流用协程,比如打电话可以切换,nginx 5 #爽妹给你打电话的时候,她不说话,刘征电话过来时候你可以切过去,这时候要是爽妹说话,就会bibi响 6 ''' 7 8 协程的好处: 9 无需线程上下文切换的开销 10 无需原子操作锁定及同步的开销 11 "原子操作(ato

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

线程 进程 协程

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