线程的有两种使用方法,一种是在函数使用,一种是放在类中使用。
1,在函数中使用多线程
语法如下:
|
thread.start_new_thread(function,args[,kwargs])
|
参数说明:
|
function-线程函数。
args-传递给线程函数的参数,必须是个tuple类型。
kwargs-可选参数。
|
下面是一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
def run(num):
print'hi , i am a thread.',num
def main():
threads=[]
foriinrange(5):
t=threading.Thread(target=run,args=(i,))
threads.append(t)
t.start()
fortinthreads:
t.join()
if__name__=='__main__':
print'start -->'
main()
print'go here -->'
|
运行结果:
|
start-->
hi,iamathread.0
hi,iamathread.1
hi,iamathread.2
hi,iamathread.3
hi,iamathread.4
go here-->
|
2,在类中多使用线程
下面是在类中使用线程的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
classMyThread(threading.Thread):
def __init__(self,num):
self.num=num
super(MyThread,self).__init__()
def run(self):
print'i am a thread,',self.num
time.sleep(1)
def main():
threads=[]
foriinrange(5):
t=MyThread(i)
threads.append(t)
t.start()
fortinthreads:
t.join()
if__name__=='__main__':
print'start -->'
main()
print'go here-->
|
-
run(),需要重写,编写代码实现所需要的功能。
-
getName(),获得线程对象名称
-
setName(),设置线程对象名称
-
start(),启动线程
-
join([timeout]),等待另一线程结束后再运行。
-
setDaemon(bool),设置子线程是否随主线程一起结束,必须在
start()
之前调用,默认为False
。
-
isDaemon(),判断线程是否随主线程一起结束。
-
isAlive(),检查线程是否在运行中。
join
方法的作用是阻塞主进程(无法执行join
以后的语句),主线程等待这个线程结束后,才可以执行下一条指令。多线程多join
的情况下,依次执行各线程的join
方法,前头一个结束了才能执行后面一个。无参数,则等待到该线程结束,才开始执行下一个线程的join
。设置参数后,则等待该线程这么长时间就不管它了(而该线程并没有结束)。不管的意思就是可以执行后面的主进程了。
3,线程同步与互斥锁
线程之所以比进程轻量,其中一个原因就是他们共享内存。也就是各个线程可以平等的访问内存的数据,如果在短时间“同时并行”读取修改内存的数据,很可能造成数据不同步。例如下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var=0
classIncreThread(Thread):
def run(self):
globalvar
print'before,var is ',var
var+=1
print'after,var is ',var
def use_incre_thread():
threads=[]
foriinrange(50):
t=IncreThread()
threads.append(t)
t.start()
fortinthreads:
t.join()
print'After 10 times,var is ',var
if__name__=='__main__':
use_incre_thread()
|
有一个全局变量var
,五十个线程,每个线程对var
变量进行加 1 运算,但是当你多运行几次后,发现并不是每次的运行结果都是 50,为什么呢?
在var
是 10 的时候,线程t1
读取了var
,这个时刻cpu
将控制权给了另一个线程t2
。t2
线程读到的var
也是 10,t1
和t2
都把var
加到 11,当时我们期望的是t1 t2
两个线程使var
+ 2 变成 12。在这里就有了资源竞争,相同的情况也可能发生在其它的线程间,所以出现了最后的结果小于 50 的情况。
为了避免线程不同步造成数据不同步,可以对资源进行加锁。也就是访问资源的线程需要获得锁,才能访问。threading
模块提供了一个 Lock
功能,修改代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
var=0
lock=Lock() #创建锁
classIncreThread(Thread):
def run(self):
globalvar
lock.acquire() #获取锁
print'before,var is ',var
var+=1
print'after,var is ',var
lock.release() #释放锁
def use_incre_thread():
threads=[]
foriinrange(50):
t=IncreThread()
threads.append(t)
t.start()
fortinthreads:
t.join()
print'After 10 times,var is ',var
if__name__=='__main__':
use_incre_thread()
|
虽然线程可以共享内存,但是一个线程不能影响其他线程内的变量(非全局变量)。
4,死锁
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。尽管死锁很少发生,但一旦发生就会造成应用的停止响应。下面是一个死锁的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
mutex_a=Lock()
mutex_b=Lock()
classMyThread(Thread):
def task_b(self):
ifmutex_a.acquire():
print'thread get a mutex_a',self.name
time.sleep(1)
ifmutex_b.acquire():
print'get a mutex_b',self.name
mutex_b.release()
mutex_a.release()
def task_a(self):
ifmutex_b.acquire():
print'thread get a mutex_b',self.name
time.sleep(1)
ifmutex_a.acquire():
print'get a mutex_a',self.name
mutex_a.release()
mutex_b.release()
def run(self):
self.task_a()
self.task_b()
if__name__=='__main__':
threads=[MyThread()foriinrange(2)]
print threads
fortinthreads:
t.start()
|
线程需要执行两个任务,两个任务都需要获取锁,当两个任务得到锁后,就需要等另外锁释放。
5,可重入锁
为了支持在同一线程中多次请求同一资源,python
提供了可重入锁(RLock
)。RLock
内部维护着一个Lock
和一个counter
变量,counter
记录了acquire
的次数,从而使得资源可以被多次require
。直到一个线程所有的acquire
都被release
,其他的线程才能获得资源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
mutex=threading.RLock()
classMyThread(threading.Thread):
def run(self):
ifmutex.acquire(1):
print'threading gte mutex:',self.name
time.sleep(1)
mutex.acquire()
mutex.release()
mutex.release()
def main():
print'start main threading:'
threads=[MyThread()foriinrange(2)]
fortinthreads:
t.start()
fortinthreads:
t.join()
print'end main threading.'
if__name__=='__main__':
main()
|
6,后台线程
使用多线程默认情况下,当主线程退出之后,即使子线程没有 join
,子线程也依然会继续执行。如果希望主线程退出后,其子线程也退出而不再执行,则需要设置子线程为后台线程。python
提供了setDaemon
方法,将子线程与主线程进行绑定,当主线程退出时子线程的生命也随之结束。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
classMyThread(threading.Thread):
def run(self):
wait_time=random.randrange(1,10)
print'thread %s will wait %s s'%(self.name,wait_time)
time.sleep(wait_time)
time.sleep(30)
print'thread %s finished.'%self.name
def main():
print'start thread:'
foriinrange(3):
t=MyThread()
t.setDaemon(1)
t.start()
print'end thread.'
if__name__=='__main__':
main()
|
运行结果:
|
start thread:
thread Thread-1will wait9s
thread Thread-2will wait1s
thread Thread-3will wait7s
endthread.
|
分享到:
相关推荐
### Python3之多线程及线程锁的基础用法 #### Python 多线程库简介 Python 提供了两种方式来支持线程:_thread 和 threading。其中,_thread 库提供了一个较为基础且底层的支持,它包含了创建简单线程的基本功能...
总的来说,理解并正确使用锁和可重入锁是解决Python多线程安全问题的关键。在编写多线程程序时,合理地引入锁机制可以防止数据竞争,确保程序的正确性。但同时,过度使用锁可能导致程序的复杂性和性能下降,因此在...
在Python编程中,多线程同步对于文件读写控制至关重要,因为如果不加以控制,多个线程同时访问同一文件可能会导致数据不一致或者错误。这里我们将深入探讨如何在Python中使用多线程同步来确保文件读写的安全性。 ...
Python多线程编程在实现网络串口透传中扮演着重要的角色,特别是在处理TCP客户端网口数据时。网络串口透传技术允许通过网络连接模拟串行通信,使得远程设备可以像连接本地串口一样进行通信。这在物联网(IoT)、远程...
在Python编程中,多线程是一种并发执行任务的机制,尤其在处理I/O密集型任务如网络请求时,能够显著提高程序效率。本教程将详细讲解如何使用Python的多线程来实现对多个网址的快速访问,并记录访问结果。 首先,...
Python多线程编程是Python系统编程中的重要组成部分,它允许程序同时执行多个任务,从而提高程序的效率和响应速度。在Python中,我们通常使用内置的`thread`库、`threading`库以及`Queue`库来实现多线程。 首先,`...
在Python编程语言中,多线程是实现并发执行任务的重要机制。它允许程序同时执行多个不同的任务,从而提高效率和响应速度。在这个基于Python的多线程例子中,我们将深入探讨如何创建和管理线程,以及如何利用它们来...
在探讨Python3中的多线程之前,我们首先需要理解线程的基本状态及其转换过程。 - **新建**: 当一个线程被创建后,它最初处于新建状态。 - **就绪**: 当线程被创建并准备好执行时,它会处于就绪状态,等待CPU分配...
总结起来,`python多线程定时器`的实现涉及到Python的`threading`和`time`模块,通过`Thread`和`Timer`类来创建和管理线程,使用定时器控制线程的启动时间。主程序`main.py`使用这些工具来安排多个任务按设定的间隔...
通过深入学习和实践压缩包中的“PYthon multithreading Test”源码,你可以更好地掌握Python多线程的原理和应用,为编写高效、稳定的多线程程序打下坚实的基础。在实际开发中,结合具体场景选择合适的并发模型,是...
本离线安装包“python多线程池离线安装包.zip”包含了实现Python多线程所需的关键组件。主要包含以下三个子文件: 1. `pip-19.2.3.tar.gz`:这是Python的包管理器pip的一个版本,用于安装和管理Python库。在离线...
在多线程编程中,我们需要注意全局解释器锁(GIL),它是Python解释器为了保证线程安全而引入的一个机制,但同时也限制了多线程在CPU密集型任务中的性能,因为GIL使得Python在同一时刻只能有一个线程在执行。...
### 利用Python SOCKET多线程开发FTP软件 在当今高度数字化的世界中,文件传输协议(FTP)作为互联网上的一项标准服务,被广泛用于在网络上进行文件传输。利用Python的socket库和多线程技术开发一个FTP软件,不仅...
通过分析和学习这个文件,你可以进一步加深对Python多线程编程的理解,包括如何有效地使用线程池(`ThreadPoolExecutor`),以及如何处理线程异常和线程间的协作问题。 总之,Python的多线程编程虽然受到GIL的限制...
此外,相比于依赖开放API的爬虫程序,基于Linux和Python多线程的爬虫程序在长期运行中显示出更好的性能。 在实现多线程爬虫时,需要考虑到多线程的同步和数据一致性问题。由于多线程程序在执行时会共享内存资源,...
Python多线程是指在Python编程语言中使用线程来执行多任务的技术。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。多线程编程是并发编程的一部分,其目的是为了提高程序的...
在Python多线程编程中,需要注意的主要问题包括线程安全和资源竞争。由于多个线程可能同时访问同一块内存,因此需要使用锁、信号量等同步机制来保护共享资源。Python的全局解释器锁(GIL)限制了在同一时刻只有一个...
但需要注意的是,Python的全局解释器锁(GIL)可能会限制多线程在CPU密集型任务中的性能提升,但在I/O密集型任务(如网络请求)中,多线程依然能发挥优势。 3. **账号密码登录**: 在登录网站进行爬取时,我们需要...
- **全局解释器锁(GIL)**:Python的CPython实现中存在GIL,这使得在同一时刻只有一个线程能够执行Python字节码,即使在多核处理器系统中,也限制了多线程并行执行的能力。因此,Python更适合于I/O密集型任务而不是...