python 多线程编程

目录

  • 0. 前言
  • 1. 实现并发
    • 1.1 创建线程
    • 1.2 线程合并——join功能
    • 1.3 全局解释器锁(GIL)
  • 2. 实现锁
    • 2.1 Queue功能——值传递
    • 2.2 线程锁
  • 3. threading函数统计表
  • 4. 参考链接

0. 前言

这篇文章我是根据【莫烦Python】Threading 学会多线程 Python的视频做的学习记录,后来又根据自己的学习进行了一定的补充。莫烦Python好帅好可爱哈哈哈。
关于线程的概念,在这里不做说明,如果想更多了解线程可以看文章末的参考链接。在学操作系统的时候,线程的描述是“CPU资源分配的基本单位”(在这里又忍不住再背以下哈哈),前段时间学了很多的用C的线程编程,所以对线程的理解比较清晰。
线程的使用是可以实现并发(线程执行是有全局解释器锁(GIL)控制,它来保证同时只有一个线程在运行,也就是说多线程并不是真正意义上的同时执行),用线程实现并发的作用即是节省I/O操作程序运行的时间,线程的创建、删除是线程中的要点之一;另外,由于线程的特性,非常适合数据的通信,因此在线程中对共享资源的管理就设计到锁的概念,目前知道的是互斥锁、队列等方式。在本篇博客就从Python怎样用线程实现并发实现锁这两个点进行整理和介绍(实现锁的部分并没有实际使用到所以还有点粗糙),用到的是threading库,不使用_thread(threading比_thread功能更强大)。

1. 实现并发

1.1 创建线程

  1. 通过创建Thread实例使用线程
    import threading
    
    
    def thread_job():
        print('This is an added Thread, number id %s' % threading.current_thread())
    
    
    def main():
        added_thread = threading.Thread(target=thread_job)  # 创建线程
        added_thread.start()  # 启动线程
    
    
    if __name__ == '__main__':
        main()
    
  2. 通过继承Thread类使用线程
    import threading
    import time
    
    class my_thread_class(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
    
        def run(self):
            '''
            重写Thread类里面的run方法 
            里面写入你需要执行的代码
            之后使用start()方法就可以调用run
            '''
            pass
    
    my_thread = my_thread_class()
    my_thread.start() # 执行线程
    
  3. threading的其他方法(method)
    threading.currentThread() # 返回当前的线程变量。
    threading.enumerate() # 返回一个包含正在运行的线程的list。。
    threading.activeCount() # 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
    

1.2 线程合并——join功能

在主程序中阻塞等待线程结束再继续执行。

import threading
import time


def thread_job():
    print('T1 start')
    for i in range(10):
        time.sleep(0.1)
    print('T1 finish')


def t2_job():
    print('T2 start')
    print('T2 finish')


def main():
	# 创建一个名字为T1,运行代码为thread_job的线程
    added_thread = threading.Thread(target=thread_job, name='T1')
    # 创建运行代码为t2_job的线程
    thread2 = threading.Thread(target=t2_job)
    added_thread.start()
    thread2.start()
    # 合并运行代码为thread_job的线程
    added_thread.join()
    # 合并运行代码为t2_job的线程
    thread2.join()
    print('all down!')


if __name__ == '__main__':
    main()

1.3 全局解释器锁(GIL)

这个只是顶层实现线程的一个概念,实际并不要编程处理。

CPython 解释器本身就不是线程安全的,因此有全局解释器锁(GIL),一次只允许使用一个线程执行Python 字节码。因此,一个Python 进程通常不能同时使用多个CPU 核心。
编写Python 代码时无法控制GIL;不过执行耗时的任务时,可以使用一个内置的函数或一个使用C 语言编写的扩展释放GIL。其实,有个使用C 语言编写的Python 库能管理GIL,自行启动操作系统线程,利用全部可用的CPU 核心。这样做会极大地增加库代码的复杂度,因此大多数库的作者都不这么做
然而,标准库中所有执行阻塞型I/O 操作的函数,在等待操作系统返回结果时都会释放GIL。这意味着在Python 语言这个层次上可以使用多线程,而I/O 密集型Python 程序能从中受益:一个Python 线程等待网络响应时,阻塞型I/O 函数会释放GIL,再运行一个线程。
因此David Beazley 才说:“Python 线程毫无作用。”
Python 标准库中的所有阻塞型I/O 函数都会释放GIL,允许其他线程运行。
time.sleep() 函数也会释放GIL。因此,尽管有GIL,Python 线程还是能在
I/O 密集型应用中发挥作用。
——《流畅的python》17.2

2. 实现锁

2.1 Queue功能——值传递

可以往线程里面传递参数,但是线程不能有返回值。
以下实例的目的是将data列表中的值全部平方:

import threading
import time
from queue import Queue

# 需要修改的列表数据
data = [[1, 2, 3], [3, 4, 5], [4, 4, 4], [5, 5, 5]]


# 定义一个功能函数,将列表中的值平方
def job(l):
    for i in range(len(l)):
        l[i] = l[i]**2
    return l


# 如果不用多线程,用以下方式实现
def no_threading():
    result = []
    for d in data:
        r = job(d)
        result.append(r)
    print(result)


def job2(l, q):
    for i in range(len(l)):
        l[i] = l[i]**2
    q.put(l)


def multithreading():

    q = Queue()
    threads = []
    # 启动线程
    for i in range(4):
        t = threading.Thread(target=job2, args=(data[i], q))
        t.start()
        threads.append(t)
    # 回收线程
    for thread in threads:
        thread.join()

    # 获取数据
    results = []
    for _ in range(4):
        results.append(q.get())
    print(results)


if __name__ == '__main__':
    # no_threading()
    multithreading()
    

2.2 线程锁

import threading


def job1():
    global A, lock
    lock.acquire()
    for i in range(10):
        A += 1
        print('job1', A)
    lock.release()


def job2():
    global A, lock
    lock.acquire()
    for i in range(10):
        A += 10
        print('job2', A)
    lock.release()


if __name__ == '__main__':
    A = 0
    lock = threading.Lock()
    t1 = threading.Thread(target=job1)
    t2 = threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

3. threading函数统计表

函数名 功能
threading.Thread() 创建线程
threading.active_count() 目前有多少个激活的线程
threading.enumerate() 激活的线程是哪几个
threading.current_thread() 正在运行的是哪个线程

4. 参考链接

以下参考链接阅读的复杂性依次提高:
Python多线程库threading的使用
Python threading实现多线程 基础篇
Python内置库:threading(多线程)
threading — 基于线程的并行

你可能感兴趣的:(Python里的碰撞,python,开发语言)