社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

这样学 Python 多线程与进程(一)

AirPython • 4 年前 • 217 次点击  
点击上方“AirPython”,选择“置顶公众号”
第一时间获取 Python 技术干货!



阅读文本大概需要 5 分钟。


众所周知,Python 中的多线程是一个假的多线程,对于多核 CPU,由于受限于 GIL 全局解释锁,同一时刻只能有一个线程在运行。

但是对于经常爬虫网络请求、下载图片等 IO 密集型操作,多线程变的很实用,能在一定程度上提高程序运行的效率。

下面带大家从零开始学习 Python 多线程。


1、单线程

在单线程程序中可能包含多个方法,运行程序后,默认是在一个主线程里按顺序运行。

import time

def exe_time(func):
    def new_func(*args, **args2):
        t0 = time.time()
        print("@%s, {%s} start" % (time.strftime("%X", time.localtime()), func.__name__))
        back = func(*args, **args2)
        print("@%s, {%s} end" % (time.strftime("%X", time.localtime()), func.__name__))
        print("@%.3fs taken for {%s}" % (time.time() - t0, func.__name__))
        return back

    return new_func

@exe_time
def func1():
    time.sleep(1)
    print('执行方法1')
    time.sleep(2)


@exe_time
def func2():
    time.sleep(1)
    print('执行方法2')
    time.sleep(2)


if __name__ == "__main__":
    func1()
    func2()

很明显,如果方法内部都是耗时的操作,会显得效率很低下。


2、IO 密集型和 CPU 密集型

涉及到网络、磁盘 IO 任务的都属于IO 密集型,比如:读写文件、网络请求等任务,计算量小。

CPU 密集型主要消耗 CPU 资源,比如:复杂的计算操作、视频高清解码等

对于爬虫来说,大部分操作时间都花在 IO 上,CPU 运算的时间很少,因此多线程还是很实用。


3、多线程

只有在 IO 操作时,线程才会主动释放掉 GIL,对于爬虫操作来说,网络请求和文件下载都属于 IO 操作。


多线程最常见的用法是自定义 threading.Thread 的子类,重写 run() 方法,然后调用 start() 函数启动线程。

import threading
import time

class thread1 (threading.Thread):

    def run(self):
          # IO操作1
          pass

class thread2(threading.Thread):
    def run(self):
          # IO操作2
          pass

if __name__ == '__main__':
    t1 = thread1()
    t2 = thread2()

    t1.start()
    t2.start()

4、全局变量和线程锁


多线程都是在同一个进程中运行的,对于进程中的全局变量也是共享的。

由于线程执行的无序性,多个线程如果要修改全局变量时,可能导致脏数据,因此需要利用到线程锁。

import threading

global_value = 0

# 线程锁
thread_lock = threading.Lock()

def add_value():
    # 全局变量
    global global_value

    # 上锁
    gLock.acquire()

    # 修改全局变量的操作
    pass

    # 释放锁
    gLock.release()

if __name__ == '__main__':
    # 定义两个线程,同时去调用一个方法去改变全局变量的值
    thread1 = threading.Thread(target=add_value)
    thread2 = threading.Thread(target=add_value)

    thread1.start()
    thread2.start()



推荐阅读


摸鱼篇 | 这款自动化工具带你高效做事,优雅摸鱼

自动化篇 | 你想要的闲鱼日常操作,Python 给你实现了

Python 还你一块纯洁无暇的移动硬盘




THANDKS
- End -
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/51198
 
217 次点击