Python多线程代码执行重复

最近在学习多线程的时候,代码书写逻辑不对,导致线程总是执行重复的操作,,记录一下自己遇到的创建线程的几种方式.

线程(thread)是进程(process)中的一个实体,一个进程至少包含一个线程。比如,对于视频播放器,显示视频用一个线程,播放音频用另一个线程。如果我们把进程看成一个容器,则线程是此容器的工作单位。

进程和线程的区别主要有:

进程之间是相互独立的,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,但互不影响;而同一个进程的多个线程是内存共享的,所有变量都由所有线程共享;

由于进程间是独立的,因此一个进程的崩溃不会影响到其他进程;而线程是包含在进程之内的,线程的崩溃就会引发进程的崩溃,继而导致同一进程内的其他线程也崩溃.

多线程

在Python中,进行多线程的编程模块有两个: thread和threadding,,前者是低级模块,后者是高级模块,经常用的是高级模块,是对thread的封装,/

 

锁机制:

由于同一个进程之间的线程是内存共享的,所以当多个线程对同一个变量进行修改的时候,就会得到意想不到的结果。

先看一个简单例子: 

# 多线程简单例子
from threading import Thread, current_thread

num = 0


def calc():
    global num
    print('thread %s is running...' % current_thread().name)  # 输出线程名
    for _ in range(100000):
        num += 1
    print('thread %s end.....' % current_thread().name)
if __name__ == '__main__':
    print('thread %s is running...' % current_thread().name)
    threads=[] #创建线程池
    for i in range(5):
        threads.append(Thread(target=calc))# 添加线程
        threads[i].start()#启动线程
    for i in range(5):
        threads[i].join()
    print('global num: %d' % num)

在上面的代码中,我们创建了 5 个线程,每个线程对全局变量 num 进行 10000 次的 加 1 操作,这里之所以要循环 10000 次,是为了延长单个线程的执行时间,使线程执行时能出现中断切换的情况。现在问题来了,当这 5 个线程执行完毕时,全局变量的值是多少呢?是 50000 吗?不一定是:

原因是 num + 1不是一个原子操作,也就是在执行的时候是被分成若干步执行了,

由于线程是交替运行的,线程在执行过程中可能会中断,导致其他线程读到一个脏值,

为了保证计算的准确性,我们就需要给 num += 1 这个操作加上 锁 。当某个线程开始执行这个操作时,由于该线程获得了锁,因此其他线程不能同时执行该操作,只能等待,直到锁被释放,这样就可以避免修改的冲突。创建一个锁可以通过 threading.Lock() 来实现,代码如下:

# 多线程简单例子
from threading import Thread, current_thread,Lock

num = 0
lock=Lock()

def calc():
    global num
    print('thread %s is running...' % current_thread().name)  # 输出线程名
    for _ in range(100000):
        lock.acquire() #加锁
        num += 1
        lock.release()#解锁
    print('thread %s end.....' % current_thread().name)
if __name__ == '__main__':
    print('thread %s is running...' % current_thread().name)
    threads=[] #创建线程池
    for i in range(5):
        threads.append(Thread(target=calc))# 添加线程
        threads[i].start()#启动线程
    for i in range(5):
        threads[i].join()
    print('global num: %d' % num)

Python多线程需要注意的几种情况:

1.采用创建指定进程数量来去处理项目,不采用传参和全局变量控制方式,

import time
from threading import Thread, current_thread, Lock
def add():
    for i in range(1,255):
        ip_h='192.168.181.'
        ip=ip_h+str(i)
        print(ip)
        ips.append(ip)


if __name__ == '__main__':
    start=time.time()
    ips=[]

    threads=[]
    for i in range(5):
        t=Thread(target=add,)
        threads.append(t)
        t.start()
    for i in threads:
        i.join()
    end=time.time()
    print("总时间"+str(start-end))

 可以看到在这种情况下,线程会重复执行,里面会有重复项出现,但执行的时间变短,但经常这种方式,不是我们想要的,因为我们不需要重复,而是直接依次的向下处理.造成这种结果的原因是,线程之间没有锁机制,然后线程之间采用并行结构,所以当线程1在处理第一个的时候,后面的都不会影响,都是从1开始处理,.

2,创建的线程是与需要的参数相关,想当于创建了254个线程,去同时执行,且在没有加锁的状态下,

import time
from threading import Thread, current_thread, Lock
def add(i):
    # for i in range(1,255):
        ip_h='192.168.181.'
        ip=ip_h+str(i)
        print(ip)
        ips.append(ip)


if __name__ == '__main__':
    start=time.time()
    ips=[]

    threads=[]
    for i in range(255):
        t=Thread(target=add,args=(i,))
        threads.append(t)
        t.start()
    for i in threads:
        i.join()
    end=time.time()
print("总时间"+str(start-end))

.而这种写法,是将线程创建和参数值关联起来,每一个线程每次只会拿到一个参数值进行处理,处理结束后,整个线程 也就结束了,所以不会有重复的出现,但这种方式,处理线程并发数与参数有关,且并发量过高,如果其中有局部变量的情况下,会每次修改掉这个局部变量.对于这种情况需要采用其他方式,如:Python 提供了 ThreadLocal 对象,它真正做到了线程之间的数据隔离.

3,采用全局变量方式,对线程处理数进行限制,这样,一个线程每一次只能拿到一个值,且这个值还是进过累加的,也就不会产生重复执行的情况.

不加锁: 

#(2)创建指定线程,通过全局变量方式,控制线程不执行重复操作
import time
from threading import Thread, current_thread, Lock
def add():
        global num #全局变量关键字
        ip_h = '192.168.181.'
        for i in range(51): # 这里的i是用来限制单个线程的所用到的循环次数,通过 处理项目总数/线程数 算出来的
                # lock.acquire()
                ip=ip_h+str(num)    #这里是控制线程执行顺序,当下一次线程进来,也只能只能执行,下一次项目,不会再重复处理之前的值
                num += 1
                # lock.release()
                print(ip)
                ips.append(ip)



if __name__ == '__main__':
    start=time.time()
    lock=Lock()
    num=1
    ips=[]
    threads=[]
    for i in range(5):
        t=Thread(target=add,)
        threads.append(t)
        t.start()
    for i in threads:
        i.join()
    end=time.time()
    print("总时间"+str(start-end))

 加锁情况下:

 可以看到时间上还是有一定差距的.

 

 

 

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Python 加快代码执行的方法有很多种。首先,可以使用更高效的算法和数据结构来提升代码执行速度。这需要对问题进行分析和优化,选择更合适的算法和数据结构来解决问题。可以通过避免不必要的循环和重复计算来降低算法的时间复杂度。通过使用适当的数据结构,如字典、集合和列表,可以减少查找和操作的时间。 其次,可以使用内置函数和模块来加快代码执行Python 提供了很多内置函数和模块,这些函数和模块经过优化,可以提高代码执行效率。例如,使用列表生成式代替循环操作,使用内置的排序函数代替手动排序等。 还可以使用并行计算的方式来加速代码执行Python 提供了多线程和多进程的支持,可以利用多核处理器的并行计算能力来加速代码执行。可以使用 threading 和 multiprocessing 模块来创建多线程和多进程,从而实现并行计算。 此外,可以使用一些第三方库来优化代码执行。例如,使用 NumPy 库来进行数值计算,使用 Pandas 库来进行数据处理,使用 Cython 来将 Python 代码编译成 C 代码等。这些库经过优化,可以提供更高效的算法和数据结构,从而加快代码执行速度。 总之,通过选择合适的算法和数据结构、使用内置函数和模块、进行并行计算以及使用第三方库等方法,都可以帮助加快 Python 代码执行速度。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴爃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值