Python多线程开发学习笔记
目录
- 更多分享:http://www.catbro.cn
前言:
- 我们在前面学习了Python 多进程开发相关的知识。
- 我们知道,多任务我们可以通过多进程完成,当然你也可以在一个进程中创建多个线程来完成。
- 本次我们将学习Python 多线程开发相关的知识。
多进程与多线程的不同点
- 多进程中,同一个变量,每个进程都有一份拷贝存在于每个进程中,进程间互不影响,
- 多线程中,所有变量都由所有线程共享。所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,造成数据错乱。
Python中的多线程
-
Python的标准库提供了两个模块:
-
1、_thread :低级模块。
-
2、threading :高级模块,对_thread进行来封装,绝大部分情况下我们只需要使用该模块即可
-
示例代码如下:
import time,threading,random; def run_thread(): print('current thread %s is running。。。' % threading.current_thread().name) i = 0 while i < 3: i += 1 print('current thread %s ,value is %s' % (threading.current_thread().name, i)) time.sleep(random.random()) print('current thread %s ended...' % threading.current_thread().name) print('current thread %s is running...' % threading.current_thread().name) t = threading.Thread(target=run_thread, ) t.start() t.join() print('current thread %s ended.' % threading.current_thread().name)
-
运行结果如下:
current thread MainThread is running... current thread Thread-1 is running。。。 current thread Thread-1 ,value is 1 current thread Thread-1 ,value is 2 current thread Thread-1 ,value is 3 current thread Thread-1 ended... current thread MainThread ended.
-
结果解析:
-
可以看到,我们当前的线程名为 MainThread,创建的线程为Thread-1.
-
为什么默认线程教MainThread呢?
-
因为每个进程创建时都会默认创建一个子线程,该线程由Python命名为MainThread。
-
当然我们自己创建的线程也可以自己命名,通过传入参数name=xxxx即可,如果不传入,则默认从Thread-1开始后面的数字递增。
-
如此我们就完成了多线程的创建及调用
多线程并发产生的问题
-
多线程很容易产生数据错误的问题,因为在同一进程中的变量对于该进程内的线程来说,都是共享的,一旦多个线程同时修改相同的变量,问题就来了。
-
我们看的示例代码(希望每个线程加1后输出,理想下是输出 1 2 3):
import time,threading,random; t_v = 0; def run_thread(): global t_v; t_v+=1; time.sleep(random.random()) print('current thread %s is running...'% threading.current_thread().name) print('current thread %s ended. value is %d' % (threading.current_thread().name,t_v)); print('current thread %s is running...' % threading.current_thread().name) t1 = threading.Thread(target=run_thread, ) t2 = threading.Thread(target=run_thread, ) t3 = threading.Thread(target=run_thread, ) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join() print('current thread %s ended.' % threading.current_thread().name)
-
运行结果如下:
current thread MainThread is running... current thread Thread-3 is running... current thread Thread-3 ended. value is 3 current thread Thread-2 is running... current thread Thread-2 ended. value is 3 current thread Thread-1 is running... current thread Thread-1 ended. value is 3 current thread MainThread ended.
-
结果分析:然而,最后输出的都是3,为什么呢?因为三个线程加1后都随机休眠了一定时间才输出,这样,在输出前,t_v被加了三次。所以最后输出的都是3
-
那么我们该如何解决呢?
-
当然是So Easy了。
Lock
-
众多支持多进程、线程开发的编程语言都会有引入锁这一概念去去处理共享问题,
-
Ok,我们来看看Python中的锁是如何使用的呢?
-
代码修改如下(在操作t_v前对当前线程上锁,输出后再释放):
import time,threading,random; t_v = 0; lock = threading.Lock(); def run_thread(): try: lock.acquire(); global t_v; t_v+=1; time.sleep(random.random()) print('current thread %s is running...'% threading.current_thread().name) print('current thread %s ended. value is %d' % (threading.current_thread().name,t_v)); except Exception as e: print(e) finally: lock.release(); print('current thread %s is running...' % threading.current_thread().name) t1 = threading.Thread(target=run_thread, ) t2 = threading.Thread(target=run_thread, ) t3 = threading.Thread(target=run_thread, ) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join() print('current thread %s ended.' % threading.current_thread().name)
-
结果输出为:
current thread MainThread is running... current thread Thread-1 is running... current thread Thread-1 ended. value is 1 current thread Thread-2 is running... current thread Thread-2 ended. value is 2 current thread Thread-3 is running... current thread Thread-3 ended. value is 3 current thread MainThread ended.
-
OK,问题就这么简单的解决了。
-
使用 try finally是保证锁最后一定会被释放,一定要注意哦,如果不释放就会产生死锁了。