searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Python并发编程(二)

2023-09-08 09:30:33
2
0

上一篇博客介绍了Python并发编程的基本知识,感兴趣的可以到专利找到上一篇文章,本文主要介绍如何开启多线程,以及多线程在提升效率的同时会存在哪些问题

Python通过标准库的 threading 模块来管理线程。这个模块提供了很多不错的特性,让线程变得无比简单,打开threading.py文件,可以到如下类或者方法

线程模块常用的主要组件有,Thread、Event、Lock、RLock、Semaphore、Timer等等,他们可以用来开启线程、保证线程间的安全、线程间的通信等等

使用线程最简单的一个方法是,用一个目标函数实例化一个Thread然后调用 start() 方法启动它。示例如下

import threading

def function(i):
    print ("function called by thread %i\n" % i)
    return

threads = []

for i in range(5):
    t = threading.Thread(target=function , args=(i, ))
    threads.append(t)
    t.start()
    t.join()

上述代码就可以开启5个线程执行function函数

Thread()参数解释如下

  • group: 一般设置为 None ,这是为以后的一些特性预留的

  • target: 当线程启动的时候要执行的函数

  • name: 线程的名字,默认会分配一个唯一名字 Thread-N

  • args: 传递给 target 的参数,要使用tuple类型

  • kwargs: 同上,使用字典类型dict

Thread类定义的常用方法如下

  1. start(): 启动线程,并执行 run() 方法。

  2. run(): 线程启动后执行的方法,可以在子类中重写。

  3. join([timeout]): 等待线程结束,可选参数 timeout 指定最长等待时间。

  4. is_alive(): 判断线程是否仍然存活。

  5. name: 线程名称的属性,可以在实例化时指定或修改。

  6. setDaemon(daemonic): 设置线程是否为守护线程,默认为 False。守护线程会在主线程结束时自动退出。

  7. getName(): 获取线程名称。

  8. setName(name): 设置线程名称。

多个线程操作同一个资源,并且至少有一个可以改变数据,又没有同步机制的条件下,就会产生竞争条件,可能会导致执行无效代码、bug、或异常行为。

这时候可以用Lock来保持线程同步,例如下列代码,在下面的代码中,我们有两个函数: increment()decrement() 。第一个函数对共享资源执行加1的操作,另一个函数执行减1.两个函数分别使用线程封装。除此之外,每一个函数都有一个循环重复执行操作。我们想要保证,通过对共享资源的管理,执行结果是共享资源最后等于初始值0.

# -*- coding: utf-8 -*-

import threading

shared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 10000000
shared_resource_lock = threading.Lock()

# 有锁的情况
def increment_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock += 1
        shared_resource_lock.release()

def decrement_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock -= 1
        shared_resource_lock.release()

# 没有锁的情况
def increment_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock += 1

def decrement_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock -= 1

if __name__ == "__main__":
    t1 = threading.Thread(target=increment_with_lock)
    t2 = threading.Thread(target=decrement_with_lock)
    t3 = threading.Thread(target=increment_without_lock)
    t4 = threading.Thread(target=decrement_without_lock)
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()
    print ("the value of shared variable with lock management is %s" % shared_resource_with_lock)
    print ("the value of shared variable with race condition is %s" % shared_resource_with_no_lock)

输出

the value of shared variable with lock management is 0
the value of shared variable with race condition is -242686

可以看到未加锁的程序出现了错误,如果你运行了示例代码没有出错,可以把COUNT值调大试试

但加锁有什么缺点呢,第一会消耗资源,第二如果程序中有多个锁存在,可能会造成死锁,导致程序一直卡住,我们设有两个并发的线程( 线程A线程B ),需要 资源1资源2 .假设 线程A 需要 资源1线程B 需要 资源2 .在这种情况下,两个线程都使用各自的锁,目前为止没有冲突。现在假设,在双方释放锁之前, 线程A 需要 资源2 的锁, 线程B 需要 资源1 的锁,没有资源线程不会继续执行。这就出现了死锁问题。

下篇文章介绍如何解决多线程的死锁问题

0条评论
0 / 1000
张****宇
5文章数
0粉丝数
张****宇
5 文章 | 0 粉丝
原创

Python并发编程(二)

2023-09-08 09:30:33
2
0

上一篇博客介绍了Python并发编程的基本知识,感兴趣的可以到专利找到上一篇文章,本文主要介绍如何开启多线程,以及多线程在提升效率的同时会存在哪些问题

Python通过标准库的 threading 模块来管理线程。这个模块提供了很多不错的特性,让线程变得无比简单,打开threading.py文件,可以到如下类或者方法

线程模块常用的主要组件有,Thread、Event、Lock、RLock、Semaphore、Timer等等,他们可以用来开启线程、保证线程间的安全、线程间的通信等等

使用线程最简单的一个方法是,用一个目标函数实例化一个Thread然后调用 start() 方法启动它。示例如下

import threading

def function(i):
    print ("function called by thread %i\n" % i)
    return

threads = []

for i in range(5):
    t = threading.Thread(target=function , args=(i, ))
    threads.append(t)
    t.start()
    t.join()

上述代码就可以开启5个线程执行function函数

Thread()参数解释如下

  • group: 一般设置为 None ,这是为以后的一些特性预留的

  • target: 当线程启动的时候要执行的函数

  • name: 线程的名字,默认会分配一个唯一名字 Thread-N

  • args: 传递给 target 的参数,要使用tuple类型

  • kwargs: 同上,使用字典类型dict

Thread类定义的常用方法如下

  1. start(): 启动线程,并执行 run() 方法。

  2. run(): 线程启动后执行的方法,可以在子类中重写。

  3. join([timeout]): 等待线程结束,可选参数 timeout 指定最长等待时间。

  4. is_alive(): 判断线程是否仍然存活。

  5. name: 线程名称的属性,可以在实例化时指定或修改。

  6. setDaemon(daemonic): 设置线程是否为守护线程,默认为 False。守护线程会在主线程结束时自动退出。

  7. getName(): 获取线程名称。

  8. setName(name): 设置线程名称。

多个线程操作同一个资源,并且至少有一个可以改变数据,又没有同步机制的条件下,就会产生竞争条件,可能会导致执行无效代码、bug、或异常行为。

这时候可以用Lock来保持线程同步,例如下列代码,在下面的代码中,我们有两个函数: increment()decrement() 。第一个函数对共享资源执行加1的操作,另一个函数执行减1.两个函数分别使用线程封装。除此之外,每一个函数都有一个循环重复执行操作。我们想要保证,通过对共享资源的管理,执行结果是共享资源最后等于初始值0.

# -*- coding: utf-8 -*-

import threading

shared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 10000000
shared_resource_lock = threading.Lock()

# 有锁的情况
def increment_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock += 1
        shared_resource_lock.release()

def decrement_with_lock():
    global shared_resource_with_lock
    for i in range(COUNT):
        shared_resource_lock.acquire()
        shared_resource_with_lock -= 1
        shared_resource_lock.release()

# 没有锁的情况
def increment_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock += 1

def decrement_without_lock():
    global shared_resource_with_no_lock
    for i in range(COUNT):
        shared_resource_with_no_lock -= 1

if __name__ == "__main__":
    t1 = threading.Thread(target=increment_with_lock)
    t2 = threading.Thread(target=decrement_with_lock)
    t3 = threading.Thread(target=increment_without_lock)
    t4 = threading.Thread(target=decrement_without_lock)
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()
    print ("the value of shared variable with lock management is %s" % shared_resource_with_lock)
    print ("the value of shared variable with race condition is %s" % shared_resource_with_no_lock)

输出

the value of shared variable with lock management is 0
the value of shared variable with race condition is -242686

可以看到未加锁的程序出现了错误,如果你运行了示例代码没有出错,可以把COUNT值调大试试

但加锁有什么缺点呢,第一会消耗资源,第二如果程序中有多个锁存在,可能会造成死锁,导致程序一直卡住,我们设有两个并发的线程( 线程A线程B ),需要 资源1资源2 .假设 线程A 需要 资源1线程B 需要 资源2 .在这种情况下,两个线程都使用各自的锁,目前为止没有冲突。现在假设,在双方释放锁之前, 线程A 需要 资源2 的锁, 线程B 需要 资源1 的锁,没有资源线程不会继续执行。这就出现了死锁问题。

下篇文章介绍如何解决多线程的死锁问题

文章来自个人专栏
python并发编程
5 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0