python多线程

1、线程创建

创建线程有两种方式,一种是直接使用threading模块中的类进行创建,另一种是继承threading模块的类写一个类来对进程进行创建。 

threading.Thread(target=None, name=None, args=(), kwargs={})

target 指要创建的线程的方法名,name 指给此线程命名,命名后可以调用 threading.current_thread().name 方法输出该线程的名字, args/kwargs 指 target 指向的方法需要传递的参数,必须是元组形式,如果只有一个参数,需要以添加逗号。

方法一:

import threading
import time

def job1(num):
    while True:
        num += 2
        print('{} is running >> {}'.format(threading.current_thread().name, num))
        time.sleep(2)


new_job = threading.Thread(target=job1, name='Add2', args=(100,))
new_job.start()
n = 1

while True:
    n += 1
    print('{} is running >> {}'.format(threading.current_thread().name, n))
    time.sleep(1)

方法二:

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, n):
        super().__init__() #必须调用父类的初始化方法
        self.n = n

    def run(self) -> None:
        while True:
            self.n += 2
            print('{} is running >> {}'.format(threading.current_thread().name, self.n))
            time.sleep(2)

new_job = MyThread(100)
new_job.setName("Add2")
new_job.start()
n = 1
while True:
    n += 1
    print('{} is running >> {}'.format(threading.current_thread().name, n))
    time.sleep(1)

输出结果:

Add2 is running >> 102
MainThread is running >> 2
MainThread is running >> 3
Add2 is running >> 104
MainThread is running >> 4
MainThread is running >> 5
Add2 is running >> 106
MainThread is running >> 6
MainThread is running >> 7
Add2 is running >> 108
MainThread is running >> 8
MainThread is running >> 9
Add2 is running >> 110
...

2、守护线程

若当前线程是守护线程,主线程结束,守护线程没有运行完,但会被强制结束;若当前线程是非守护线程,主线程只有等到非守护线程运行完毕才能结束。

import threading
import time

# 每1秒加1
def job1(num):
    while num < 105:
        num += 1
        print('{} is running >> {}'.format(threading.current_thread().name, num))
        time.sleep(1)
    print("job1 Endding")

# 每2秒加2
def job2(num):
    while True:
        num += 2
        print('{} is running >> {}'.format(threading.current_thread().name, num))
        time.sleep(2)

# 线程1,一秒加一
new_job1 = threading.Thread(target=job1, name='Add1', args=(100,))
new_job1.start()

# 线程2,两秒加二
new_job2 = threading.Thread(target=job2, name='Add2', args=(1,))
# 设置为守护线程
new_job2.setDaemon(True)
new_job2.start()

# 主线程等待job1执行完成
# new_job1.join()
print('{} Ending'.format(threading.current_thread().name))

个人理解:只要当前主线程中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着主线程一同结束。

运行结果:

Add1 is running >> 101
Add2 is running >> 3
MainThread Ending
Add1 is running >> 102
Add2 is running >> 5
Add1 is running >> 103
Add1 is running >> 104
Add2 is running >> 7
Add1 is running >> 105
job1 Endding

3、阻塞线程

join()方法会使线程进入等待状态,直到调用join()方法的子线程运行结束,可通过timeout参数设定等待时间。

注意,join方法只能写在start方法之后。

在示例2的基础上,取消new_job1.join()的注释,输出结果为:

Add1 is running >> 101
Add2 is running >> 3
Add1 is running >> 102
Add1 is running >> 103
Add2 is running >> 5
Add1 is running >> 104
Add1 is running >> 105
Add2 is running >> 7
job1 Endding
MainThread Ending

4、线程锁

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的准确性,需对多个线程进行同步,确保同一时间只有一个线程可以访问被锁定的代码块,从而避免线程间的竞争条件和数据不一致的问题。

acquire()方法获取锁;release()方法释放锁;

互斥锁(Lock):

互斥锁只能开一次然后释放一次,一次开启后必须接上一次关闭。

import threading
import time


num = 0

lock = threading.Lock()

def job1():
    global num
    for i in range(5):
        lock.acquire() # 加锁
        num += 1
        print("job1")
        print(num)
        lock.release() # 释放锁
        # 上述代码也可以直接写为
        # with lock:
        # 	 num += 1

new_job1 = threading.Thread(target=job1, name='Add1')
new_job1.start()

for i in range(5):
    lock.acquire() # 加锁
    num += 2
    print("*****************")
    print(num)
    lock.release() # 释放锁

# 等待线程执行完毕
time.sleep(3)
print('num = {}'.format(num))

运行结果:

job1
1
job1
2
job1
3
job1
4
job1
5
*****************
7
*****************
9
*****************
11
*****************
13
*****************
15
num = 15

递归锁(RLock): 

递归锁可以开多次,再进行多次释放,RLock支持大锁里套小锁。

import threading, time

def run1():
    lock.acquire()
    print("grab the first part data")
    global num
    num += 1
    lock.release()
    return num

def run2():
    lock.acquire()
    print("grab the second part data")
    global num2
    num2 += 1
    lock.release()
    return num2

def run3():
    lock.acquire()
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()
    print(res, res2)

if __name__ == '__main__':
    num, num2 = 0, 0
    lock = threading.RLock()
    for i in range(3):
        t = threading.Thread(target=run3)
        t.start()

 运行结果:

grab the first part data
--------between run1 and run2-----
grab the second part data
1 1
grab the first part data
--------between run1 and run2-----
grab the second part data
2 2
grab the first part data
--------between run1 and run2-----
grab the second part data
3 3
  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值