Python多线程(上)

前言

说起Python的多线程,很多人都嗤之以鼻,说Python的多线程是假的多线程,没有用,或者说不好用,那本次就和大家一起来分享一下Python的多线程,看看是不是这样的。

相关概念

线程(Thread)也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属的一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发执行。

多线程语法

在Python中实现多线程编程需要用到的就是threading模块中的Thread类,我们来看看最简单的语法,我们首先来一个简单的函数。

def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(count)


nums = [100, 1000, 10000]
for num in nums:
    task(num)

# 100
#1000
#10000

我们用三个子线程分别计算。

import threading


def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(count)


nums = [100, 1000, 10000]
for num in nums:
    t = threading.Thread(target=task, args=(num,))
    t.start()

利用Thread创建线程,target参数接收函数名,args参数接收函数的参数,start方法启动线程。

这里还需要讲解一下join方法,他的作用是让主线程等待,直到该子线程结束。我们来看看加该方法和不加该方法,最终的结果是怎么样的。

import threading


def task():
    num = 0
    for i in range(10000000):
        num += 1
    print(num)


t = threading.Thread(target=task)
t.start()
print('end')

# end
# 10000000
import threading


def task():
    num = 0
    for i in range(10000000):
        num += 1
    print(num)


t = threading.Thread(target=task)
t.start()
t.join()
print('end')

# 10000000
# end

GIL

在说概念之前,我们还是以上面的代码为例,分别求单线程和多线程代码运行的时间。

单线程

import time


def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(count)


nums = [1000000, 100000000, 1000000000]
start = time.time()
for num in nums:
    task(num)
end = time.time()
print(end - start)

# 50.44705629348755

多线程

import threading
import time


def task(num):
    count = 0
    for i in range(num):
        count += 1
    print(count)


nums = [1000000, 100000000, 1000000000]
ts = []
start = time.time()

for num in nums:
    t = threading.Thread(target=task, args=(num,))
    t.start()
    ts.append(t)

for t in ts:
    t.join()

end = time.time()
print(end - start)

# 55.022353172302246

你会发现多线程比单线程花费的时间还要更多,这是因为GIL的原因。

GIL的全称是Global Interpreter Lock(全局解释器锁),Python最初的设计理念在于,为了解决多线程之间数据完整性和状态同步的问题,设计为在任意时刻只能由一个线程在解释器中运行。因此Python中的多线程是表面上的多线程(同一时刻只有一个线程),不是真正的多线程。

但是如果是因为GIL的原因,就说多线程无用是不对的,对于IO密集的程序,多线程是要比单线程快的。我们举一个简单的爬虫案例。

单线程

import time


def task(url):
    s = url.split('_')[-1]
    time.sleep(int(s)) #这里模拟请求等待


urls = ['url_1', 'url_2', 'url_3']
start = time.time()
for url in urls:
    task(url)
end = time.time()
print(end - start)

# 6.013520002365112

多线程

import threading
import time


def task(url):
    s = url.split('_')[-1]
    time.sleep(int(s))


ts = []
urls = ['url_1', 'url_2', 'url_3']
start = time.time()

for url in urls:
    t = threading.Thread(target=task, args=(url,))
    t.start()
    ts.append(t)

for t in ts:
    t.join()
    
end = time.time()
print(end - start)

# 3.005527973175049

这时候我们就能看到多线程的优势了,虽然多线程只是在各线程来回切换,但是可以让IO堵塞的时间切换到其他线程做其他的任务,很适合爬虫或者文件的操作。

今天的分享就到这了,如果我的文章对你有帮助,别忘了点赞,收藏,转发,这对我有很大的帮助,我们下期再见~

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Python多线程的一些理解: 1.多线程采用的是分时复用技术,即不存在真正的多线程,cpu做的事是快速地切换线程...
    马尔代夫Maldives阅读 2,398评论 0 0
  • 多线程编程技术可以实现代码并行,优化处理能力,同时可以将代码划分为功能更小的模块,使代码的可重用性更好。这里将介绍...
    泷汰泱阅读 311评论 0 0
  • 1 概念梳理: 1.1 线程 1.1.1 什么是线程 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中...
    黑涩_阅读 1,014评论 0 0
  • 一、简介 什么是线程?线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际...
    CJ21阅读 3,041评论 0 6
  • 首先引用廖老师的一句话:Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。多线程的并行在Pyt...
    玩阿轲睡妲己阅读 1,641评论 0 19