多线程编程
来源:互联网 发布:手机怎么申请淘宝介入 编辑:程序博客网 时间:2024/05/21 21:38
1、
当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread),因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程。每个进程至少都有一个主线程,在Winform中,应该就是创建GUI的线程。
主线程的重要性体现在两方面:1.是产生其他子线程的线程;2.通常它必须最后完成执行比如执行各种关闭动作。
实验代码:
import threadingdef f(i): print("I am from a thread,num=%d\n"%(i));def main(): for i in range(1,10): t=threading.Thread(target=f,args=(i,));#TypeError: f() argument after * must be a sequence, not int t.setDaemon(True); t.start();if __name__=="__main__": main();
实验结果为:
结论:虽然线程的创建和启动是有顺序的,但线程是并发运行的,所以那个线程先执行完是不确定的。从运行结果可以看到,输出的数字也是没有规律的。而且在“I am from a thread, num=4",前面还有个>>>,是说明主程序在此处已经退出。
线程对象的setDaemon()方法可以让子线程随着主线程的退出而结束,不过注意的是setDaemon()方法必须在线程对象没有调用start()方法之前调用(默认情况下;在python
中,主线程结束后,会默认等待子线程结束后,主线程才退出)。
2、阻塞进程
# -*- coding: cp936 -*-import threadingdef f(i): print("I am from a thread,num=%d\n"%(i));def main(): for i in range(1,10): t=threading.Thread(target=f,args=(i,));#TypeError: f() argument after * must be a sequence, not int t.setDaemon(True); t.start(); t.join();#可以阻塞进程直到线程执行完毕。if __name__=="__main__": main();运行结果为:
可以看到,进程在所有线程结束后才退出。
3、指令锁
当多个线程同时访问同一资源(比如,全局变量),可能会出现访问冲突。
冲突:
import threadingimport timenum=0;def f(): global num; b=num; time.sleep(0.0001); num=b+1; print('%s\n'%threading.currentThread().getName());def main(): for i in range(1,20): t=threading.Thread(target=f); t.setDaemon(True); t.start(); t.join(); print(num);if __name__=="__main__": main();
实验结果为:
改进:
可以使用锁来限制线程同时访问同一资源。指令锁处于锁定状态时,不能被特定的线程所拥有。当线程申请一个处于锁定状态的锁时线程会被阻塞,直至该锁被释放。
在访问全局变量之前申请一个指令锁,在访问全局变量之后释放一个指令锁,这样就可以避免多个线程同时访问全局变量。
# -*- coding: cp936 -*-import threadingimport timelock=threading.Lock();#创建一个指令锁num=0;def f(): global num; if lock.acquire(): print('%s获得指令锁.'%threading.currentThread().getName()); b=num; time.sleep(0.0001); num=b+1; lock.release()#释放指令锁 print('%s释放指令锁.'%threading.currentThread().getName()); print('%s\n'%threading.currentThread().getName());def main(): for i in range(1,20): t=threading.Thread(target=f); t.setDaemon(True); t.start(); t.join(); print(num);if __name__=="__main__": main();实验结果:
4、可重入锁
使用指令锁可以避免多个线程同时访问全局变量。但是如果一个线程里面有递归函数,则它可能会多次请求访问全局变量,此时,即使线程已经获得指令锁,在它再次申请
指令锁时会被阻塞。每个可重入锁都关联一个请求计数器和一个占有它的线程,当请求计数器为0时,这个锁可以被一个线程请求得到并把锁的请求计数加1。如果同一个线程
再次请求这个锁,请求计数器就会增加,当该线程释放RLock时,其计数器减1,当计数器为0时,该锁被释放。
实验代码:
# -*- coding: cp936 -*-import threadingimport timelock=threading.RLock();#创建一个可重入锁num=0;def f(): global num; #第一次请求锁定 if lock.acquire(): print('%s获得指令锁.'%threading.currentThread().getName()); time.sleep(0.0001); #第二次请求锁定 if lock.acquire(): print('%s获得指令锁.'%threading.currentThread().getName()); time.sleep(0.0001); lock.release()#释放指令锁 print('%s释放指令锁.'%threading.currentThread().getName()); time.sleep(0.0001); print('%s释放指令锁.'%threading.currentThread().getName()); lock.release()#释放指令锁def main(): for i in range(1,20): t=threading.Thread(target=f); t.setDaemon(True); t.start(); t.join(); print(num);if __name__=="__main__": main();
实验结果:
>>>
Thread-1获得指令锁.
Thread-1获得指令锁.
Thread-1释放指令锁.
Thread-1释放指令锁.
Thread-2获得指令锁.
Thread-2获得指令锁.
Thread-2释放指令锁.
Thread-2释放指令锁.
Thread-3获得指令锁.
Thread-3获得指令锁.
Thread-3释放指令锁.
Thread-3释放指令锁.
Thread-4获得指令锁.
Thread-4获得指令锁.
Thread-4释放指令锁.
Thread-4释放指令锁.
Thread-5获得指令锁.
Thread-5获得指令锁.
Thread-5释放指令锁.
Thread-5释放指令锁.
Thread-6获得指令锁.
Thread-6获得指令锁.
Thread-6释放指令锁.
Thread-6释放指令锁.
Thread-7获得指令锁.
Thread-7获得指令锁.
Thread-7释放指令锁.
Thread-7释放指令锁.
Thread-8获得指令锁.
Thread-8获得指令锁.
Thread-8释放指令锁.
Thread-8释放指令锁.
Thread-9获得指令锁.
Thread-9获得指令锁.
Thread-9释放指令锁.
Thread-9释放指令锁.
Thread-10获得指令锁.
Thread-10获得指令锁.
Thread-10释放指令锁.
Thread-10释放指令锁.
Thread-11获得指令锁.
Thread-11获得指令锁.
Thread-11释放指令锁.
Thread-11释放指令锁.
Thread-12获得指令锁.
Thread-12获得指令锁.
Thread-12释放指令锁.
Thread-12释放指令锁.
Thread-13获得指令锁.
Thread-13获得指令锁.
Thread-13释放指令锁.
Thread-13释放指令锁.
Thread-14获得指令锁.
Thread-14获得指令锁.
Thread-14释放指令锁.
Thread-14释放指令锁.
Thread-15获得指令锁.
Thread-15获得指令锁.
Thread-15释放指令锁.
Thread-15释放指令锁.
Thread-16获得指令锁.
Thread-16获得指令锁.
Thread-16释放指令锁.
Thread-16释放指令锁.
Thread-17获得指令锁.
Thread-17获得指令锁.
Thread-17释放指令锁.
Thread-17释放指令锁.
Thread-18获得指令锁.
Thread-18获得指令锁.
Thread-18释放指令锁.
Thread-18释放指令锁.
Thread-19获得指令锁.
Thread-19获得指令锁.
Thread-19释放指令锁.
Thread-19释放指令锁.
0
>>>
5、信号量
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- JavaWeb项目Tomcat服务器的安装与配置[纯小白参考]
- Windows并发&异步编程(0)创建、终止进程
- 请实现一个算法,在不使用额外数据结构和储存空间的情况下,翻转一个给定的字符串(可以使用单个过程变量)
- Java中的MySQL数据库与JDBC编程笔记
- 几何变换 -- 仿射变换
- 多线程编程
- 错题总结之自减运算符
- tcpdump分析
- ES6新特性学习(一)
- 基于proteus的51单片机仿真实例七十一、并口转串口器件74HC165应用实例
- 攻击技术及临时资源汇总
- 数据结构(循环链表)实现约瑟夫问题
- HttpClient 不能做的事情
- block chain