【记录】python多线程的使用 线程同步(LOCK和RLOCK) python与mysql数据库交互实现增加和查找 python的格式化输出


多线程:

_thread模块

例一

import _thread

import time


# 为线程定义一个函数

def print_time(threadName, delay):
    count = 0

    while count < 5:
        time.sleep(delay)

        count += 1

        print("%s: %s" % (threadName, time.ctime(time.time())))


# 创建两个线程

try:

    _thread.start_new_thread(print_time, ("Thread-1", 2,))

    _thread.start_new_thread(print_time, ("Thread-2", 4,))

except:

    print("Error: 无法启动线程")

while 1:
    pass

例二:

import _thread
from time import sleep
from datetime import datetime

date_time_format='%y-%M-%d %H:%M:%S'

def date_time_str(date_time):
    return datetime.strftime(date_time, date_time_format)

def loop_one():
    print(f'+++线程一开始于:{date_time_str(datetime.now())}')
    print('+++线程一休眠4秒')
    sleep(4)
    print(f'+++线程一休眠结束,结束于:{date_time_str(datetime.now())}')

def loop_two():
    print(f'***线程二开始时间:{date_time_str(datetime.now())}')
    print('***线程二休眠2秒')
    sleep(2)
    print(f'***线程二休眠结束,结束时间:{date_time_str(datetime.now())}')

def main():
    print(f'------所有线程开始时间:{date_time_str(datetime.now())}')
    _thread.start_new_thread(loop_one, ())
    _thread.start_new_thread(loop_two, ())
    sleep(6)
    print(f'------所有线程结束时间:{date_time_str(datetime.now())}')


if __name__ == '__main__':
    main()

在这里插入图片描述
主线程一旦运行结束,就关闭运行着的其他两个线程。这可能造成主线程过早或过晚退出,这时就要使用线程锁,主线程可以在两个子线程都退出后立即退出。 示例代码如下

import _thread
from time import sleep
from datetime import datetime

loops=[4, 2]
date_time_format='%y-%M-%d %H:%M:%S'

def date_time_str(date_time):
    return datetime.strftime(date_time, date_time_format)

def loop(n_loop, n_sec, lock):
    print(f'线程({n_loop})开始执行:{date_time_str(datetime.now())},先休眠({n_sec})秒')
    sleep(n_sec)
    print(f'线程({n_loop})休眠结束,结束于:{date_time_str(datetime.now())}')
    lock.release()

def main():
    print('---所有线程开始执行...')
    locks=[]
    n_loops=range(len(loops))

    for i in n_loops:
        lock=_thread.allocate_lock()
        lock.acquire()
        locks.append(lock)

    for i in n_loops:
        _thread.start_new_thread(loop, (i, loops[i], locks[i]))

    for i in n_loops:
        while locks[i].locked(): pass

    print(f'---所有线程执行结束:{date_time_str(datetime.now())}')

if __name__ == '__main__':
    main()

threading模块:

_thread模块不支持守护线程,当主线程退出时,所有子线程无论是否在工作,都会被强行退出。threading模块支持守护线程,守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求,就一直等着。如果设定一个线程为守护线程,就表示这个线程不重要,在进程退出时,不用等待这个线程退出。如果主线程退出时不用等待子线程完成,就要设定这些线程的daemon属性,即在线程Thread.start()开始前,调用setDaemon()函数设定线程的daemon标志(Thread.setDaemon(True)),表示这个线程“不重要”。如果一定要等待子线程执行完成再退出主线程,就什么都不用做或显式调用Thread.setDaemon(False)以保证daemon标志为False,可以调用Thread.isDaemon()函数判断daemon标志的值。新的子线程会继承父线程的daemon标志,主线程在所有非守护线程退出后才会结束,即进程中没有非守护线程存在时才结束。

例子:

import threading
from time import sleep
from datetime import datetime

loops=[4, 2]
date_time_format='%y-%M-%d %H:%M:%S'

def date_time_str(date_time):
    return datetime.strftime(date_time, date_time_format)

def loop(n_loop, n_sec):
    print(f'线程({n_loop})开始执行:{date_time_str(datetime.now())},先休眠({n_sec})秒')
    sleep(n_sec)
    print(f'线程({n_loop})休眠结束,结束于:{date_time_str(datetime.now())}')
def main():
    print(f'---所有线程开始执行:{date_time_str(datetime.now())}')
    threads=[]
    n_loops=range(len(loops))

    for i in n_loops:
        t=threading.Thread(target=loop, args=(i, loops[i]))
        threads.append(t)

    for i in n_loops:      # start threads
        threads[i].start()
    for i in n_loops:  # wait for all
            threads[i].join()  # threads to finish

    print(f'---所有线程执行结束于:{date_time_str(datetime.now())}')


if __name__ == '__main__':
    main()

在这里插入图片描述
附自己修改后的代码:

import threading
from time import sleep
from datetime import datetime

loops=[2, 2]
date_time_format='%y-%M-%d %H:%M:%S'

def date_time_str(date_time):
    return datetime.strftime(date_time, date_time_format)

def loop(n_loop, n_sec):
    print(f'线程({n_loop})开始执行:{date_time_str(datetime.now())},先休眠({n_sec})秒')
    sleep(n_sec)
    print(f'线程({n_loop})休眠结束,结束于:{date_time_str(datetime.now())}')

def begin(n_loop,sec):
    print(f'线程{n_loop}开始执行:{date_time_str(datetime.now())}')
    print("begin")
    sleep(sec)
    print(f'{n_loop}休眠结束,结束于:{date_time_str(datetime.now())}')
def main():
    print(f'---所有线程开始执行:{date_time_str(datetime.now())}')
    threads=[]
    n_loops=range(len(loops))


    t=threading.Thread(target=loop, args=(1, loops[0]))
    threads.append(t)
    m=threading.Thread(target=begin,args=(2,loops[1]))
    threads.append(m)

    for i in n_loops:      # start threads
        threads[i].start()
    for i in n_loops:  # wait for all
            threads[i].join()  # threads to finish

    print(f'---所有线程执行结束于:{date_time_str(datetime.now())}')


if __name__ == '__main__':
    main()

线程同步(LOCK和RLOCK)

如果多个线程共同修改某个数据,就可能会出现不可预料的结果。为了保证数据的正确性,需要对多个线程进行同步。 使用Thread对象的Lock和RLock可以实现简单的线程同步,这两个对象都有acquire方法和release方法。对于每次只允许一个线程操作的数据,可以将操作放到acquire和release方法之间。 多线程的优势在于可以同时运行多个任务,但当线程需要共享数据时,可能存在数据不同步的问题。 考虑这样一种情况:一个列表里所有元素都是0,线程set从后向前把所有元素改成1,而线程print负责从前往后读取列表并输出。
线程set开始改的时候,线程print可能就来输出列表了,输出就成了一半0一半1,这就是数据不同步的问题。为了避免这种情况,引入了锁的概念。 锁有两种状态——锁定和未锁定。当一个线程(如set)要访问共享数据时,必须先获得锁定;如果已经有别的线程(如print)获得锁定了,就让线程set暂停,也就是同步阻塞;等到线程print访问完毕,释放锁以后,再让线程set继续。 经过这样的处理,输出列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。

示例代码:

import threading
from time import sleep
from datetime import datetime
 
date_time_format='%y-%M-%d %H:%M:%S'
 
class MyThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID=threadID
        self.name=name
        self.counter=counter
 
    def run(self):
        print(f"开启线程: {self.name}")
        # 获取锁,用于线程同步
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 释放锁,开启下一个线程
        threadLock.release()
 
 
def date_time_str(date_time):
    return datetime.strftime(date_time, date_time_format)
 
 
def print_time(threadName, delay, counter):
    while counter:
        sleep(delay)
        print(f"{threadName}: {date_time_str(datetime.now())}")
        counter -= 1
 
 
def main():
    # 创建新线程
    thread1=MyThread(1, "Thread-1", 1)
    thread2=MyThread(2, "Thread-2", 2)
 
    # 开启新线程
    thread1.start()
    thread2.start()
 
    # 添加线程到线程列表
    threads.append(thread1)
    threads.append(thread2)
 
    # 等待所有线程完成
    for t in threads:
        t.join()
    print("退出主线程")
 
 
if __name__ == "__main__":
    threadLock=threading.Lock()
    threads=[]
    main() 
 
 

和mysql交互:

增加和查询操作:

import pymysql
import time
pymysql.install_as_MySQLdb()
from sqlalchemy import create_engine,text
#定义数据库属性
hostname = '127.0.0.1'
port = '3308'
database = 'data1'
username = 'heziyi'
pwd = '123456'
dburl = 'mysql+mysqldb://{}:{}@{}:{}/{}'.format(username,pwd,hostname,port,database)
timenow= time.strftime('%Y-%m-%d',time.localtime(time.time()))
print(timenow)
#创建数据库连接对象
engine = create_engine(dburl,echo=True)
with engine.connect() as con:
 # rs = con.execute('SELECT 1')  # con.execute(text("select 1 "))


  sql = 'INSERT INTO data1.wash VALUES(10,\'15\',\'175\',\'9\',\'19.4\',\'2021-05-24\');'
  result = con.execute(
sql
 )

  result = con.execute('select * from wash')
  print(result.fetchall())

在这里插入图片描述
查询某一列:

  result = con.execute('select times,average,Time from wash')
  print(result.fetchall())

结果:
[(‘4’, 30.5, datetime.date(2021, 5, 18)), (‘5’, 28.4, datetime.date(2021, 5, 20)), (‘6’, 26.7, datetime.date(2021, 5, 21)), (‘7’, 26.0, datetime.date(2021, 5, 22)), (‘8’, 25.7, datetime.date(2021, 5, 23)), (‘9’, 19.4, datetime.date(2021, 5, 24))]

格式化插入(传入变量的方式):

timenow= time.strftime('%Y-%m-%d',time.localtime(time.time()))

#创建数据库连接对象
engine = create_engine(dburl,echo=True)
with engine.connect() as con:
  sql = 'INSERT INTO data1.wash VALUES(11,\'15\',\'175\',\'9\',\'19.4\',\'{}\');'.format(timenow)

附:python的格式化输出

多个格式化

‘b’ - 二进制。将数字以2为基数进行输出。
‘c’ - 字符。在打印之前将整数转换成对应的Unicode字符串。
‘d’ - 十进制整数。将数字以10为基数进行输出。
‘o’ - 八进制。将数字以8为基数进行输出。
‘x’ - 十六进制。将数字以16为基数进行输出,9以上的位数用小写字母。
‘e’ - 幂符号。用科学计数法打印数字。用’e’表示幂。
‘g’ - 一般格式。将数值以fixed-point格式输出。当数值特别大的时候,用幂形式打印。
‘n’ - 数字。当值为整数时和’d’相同,值为浮点数时和’g’相同。不同的是它会根据区域设置插入数字分隔符。
‘%’ - 百分数。将数值乘以100然后以fixed-point(‘f’)格式打印,值后面会有一个百分号。

print('{0:b}'.format(3))
print('{0:d}'.format(3))
print('{0:o}'.format(3))
print('{0:x}'.format(3))

在这里插入图片描述
name = ‘jack’
age = 18
sex = ‘man’
job = “IT”
salary = 9999.99

print(f’my name is {name.capitalize()}.’)
print(f’I am {age:*^10} years old.’)
print(f’I am a {sex}’)
print(f’My salary is {salary:10.3f}’)

结果
my name is Jack.
I am 18 years old.
I am a man
My salary is 9999.990

附录

关于python运行多线程的问题:
1)Python多线程的效率怎么样
答:Python有全锁局的存在(同一时间只能有一个线程执行),并不能利用多核优势。如果你的多线程进程是CPU密集型的,多线程就不能带来效率的提升,相反还可能因为线程的频繁切换导致效率下降。如果是IO密集型,多线程进程就可以利用IO阻塞等待时的空闲时间执行其他线程,从而提升效率。 (2)既然Python解释器是单线程的,还有进行多线程编程的必要吗
答:多线程最开始不是用来解决多核利用率问题的,而是用来解决IO占用时CPU闲置的问题。 多线程可以用来解决阻塞问题,可以做事件响应机制(或者类似信号槽的问题)。如果运行瓶颈不是在CPU运算而是在IO(网络)上,多线程显然很划算。 能产生IO阻塞的情况很多,如网络、磁盘等。当发生阻塞时,Python是不耗CPU的,此时如果只有一个线程就没法处理其他事情了。对于有IO阻塞的环境,多线程可能让你的CPU跑到100%。 另一个用处来自于Python的C扩展模块。在扩展模块里可以释放GIL。释放GIL期间不应该调用任何Python API。对于一些非常繁重的计算,可以写成C模块,计算前释放GIL,计算后重新申请GIL,并将结果返回给Python。这样就可以让Python进程利用更多CPU资源。每个Python线程都是OS级别的Pthread线程。利用Python管理这些线程比在C层级操作Pthread更方便。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值