Python 多线程实践总结

Python 多线程实践总结_第1张图片

Python 多线程实践总结

0 背景

多线程类似于同时执行多个不同程序,多线程运行有如下优点:
使用线程可以把占据长时间的程序中的任务放到后台去处理。
程序的运行速度可能加快
在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,可以同时进行

进程与线程:

进程是资源分配的最小单位,一个程序至少有一个进程。

线程是程序执行的最小单位,一个进程至少有一个线程。

进程都有自己独立的地址空间,内存,数据栈等,所以进程占用资源多。由于进程的资源独立,所以通讯不方便,只能使用进程间通讯(IPC)。

线程共享进程中的数据,他们使用相同的地址空间,使用线程创建快捷,创建开销比进程小。同一进程下的线程共享全局变量、静态变量等数据,所以线程通讯非常方便,但会存在数据同步与互斥的问题,如何处理好同步与互斥是编写多线程程序的难点。

一个进程中可以存在多个线程,在单核CPU中每个进程中同时刻只能运行一个线程,只有在多核CPU中才能存在线程并发的情况。

当线程需要运行但没有运行空间时,会对线程的优先级进行判断,高优先级先运行,低优先级进程让行。

1 关于并发

并发相关的python库

threading:基于线程的并行
multiprocessing:基于进程的并行
concurrent:并发包
concurrent.futures:启动并行任务
subprocess:子进程管理
sched:事件调度
queue:同步队列
select:等待I / O完成
dummy_threading:threading模块的替代(当_thread不可用时)
_thread:底层的线程API(threading基于其上)
_dummy_thread:_thread模块的替代(当_thread不可用时)

1.1 什么是线程?

​ 进程是操作系统分配程序执行资源的单位,而线程是进程的一个实体,是CPU调度和分配的单位。一个进程肯定有一个主线程,我们可以在一个进程里创建多个线程来实现多任务。

1.2 创建threading.Thread对象
import threading
p1 = threading.Thread(target=[函数名],args=([要传入函数的参数]))
p1.start()  # 启动p1线程

1.3 利用互斥锁解决线程安全

当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制

线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。

互斥锁为资源引入一个状态:锁定/非锁定

某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

​ 互斥锁有三个常用步骤:

lock = threading.Lock()  # 取得锁
lock.acquire()  # 上锁
lock.release()  # 解锁
import threading
import time

num = 0
lock = threading.Lock()  # 取得锁
def work1(loop):
    global num
    for i in range(loop):
        # 等价于 num += 1
        lock.acquire()  # 上锁
        temp = num
        num = temp + 1
        lock.release()  # 解锁
    print(num)


def work2(loop):
    global num
    for i in range(loop):
        # 等价于 num += 1
        lock.acquire()  # 上锁
        temp = num
        num = temp + 1
        lock.release()  # 解锁
    print(num)


if __name__ == '__main__':
    t1 = threading.Thread(target=work1,args=(1000000,))
    t2 = threading.Thread(target=work2, args=(1000000,))
    t1.start()
    t2.start()

    while len(threading.enumerate()) != 1:
        time.sleep(1)
    print(num)

1.4 使用Queue模块来共享资源

Python 多线程实践总结_第2张图片

from queue import Queue
from threading import Thread
import time
que = Queue()
# 如果maxsize设置为小于0或者不设置,队列为无限长
#que = Queue(maxsize=2)

def task(value):
    global que
    que.put(value)
    # que.put(value)

def task2():
    global que
    res = que.get()
    print(res)
    que.task_done()

t1 = Thread(target=task, args=(10,))
t2 = Thread(target=task2)
t1.start()
t2.start()
t1.join()
t2.join()
que.join()

2 参考Demo

这里整理了一个使用que与threading 实现并发的Demo

def main():
    start_url = Queue.Queue()  # 存放url的队列
    result_queue = Queue.Queue() # 结果集队列
    for i in range(1, 3):
        page_url = '_%s.shtml' % i
        start_url.put(page_url)  # 将值插入队列中
    # 构建线程
    thread_list = []
    for n in range(4):  # 创建4 个线程
        t_t = threading.Thread(target=get_news_url, args=(start_url, result_queue))  # 创建线程,调用get_news_url方法,args传入参数
        thread_list.append(t_t)
    for t in thread_list:
        t.start()
    start_url.join() # 就是当所有的url全部获取完,放入到结果集里才开始存入数据库,防止出现 插入数据库报错的情况
    while result_queue.qsize(): # 返回队列的大小
         save_news_mysql(result_queue.get()) # 将结果存入数据库中

3 总结

多线程可以实现并发 增强程序的处理能力

Python 多线程实践总结_第3张图片

你可能感兴趣的:(python,python,linux)