一、线程与多线程

1、线程与进程

线程指的是 进程(运行中的程序)中单一顺序的执行流。

多个独立执行的线程相加 = 一个进程

多线程程序是指一个程序中包含有多个执行流,多线程是实现并发机制的一种有效手段。

2、线程的生命周期

每个线程都要经历创建就绪运行阻塞死亡等5个状态,线程从产生到消失的状态变化称之为生命周期

从图中可以看到,一个线程的生命周期一般经过如下步骤:

  • 一个线程通过实例化创建线程对象后,进入新生状态。
  • 线程对象通过调用 start()方法进入就绪状态,一个处在就绪状态的线程将被调度执行,执行该线程相应的run()方法中的代码。
  • 通过调用线程的(或从 Object类继承过来的)sleep()wait()suspent()方法,这个线程进入阻塞状态。一个线程也可能自己完成阻塞操作。
  • run()方法执行完毕,或者有一个例外产生,或者执行 System. exit() 方法,则一个线程就进入死亡状态。
方法 说明
_ _ init _ _(self,name=threadname) 初始化方法,threadname为线程名称
run() 编写线程代码,实现线程所有要完成的功能
getName() 获得线程对象名字
setName() 设置线程对象名字
start() 启动线程
jion([timeout]) 等待另一线程结束后再运行
setDaemon(bool) 子线程是否随主线程一起结束,必须在start()之前调用,默认false
isAlive() 检查线程是否在运行中

3、创建线程

Python中,可采用两种方式创建线程:

  • 应用Thread类的构造函数创建一个多线程对象
  1. import threading
  2. def fun(i):
  3. print("thread id = %d \n" %i)
  4. def main():
  5. for i in range(1,10):
  6. t = threading.Thread(target=fun, args=(i,))
  7. t.start()
  8. if __name__ == "__main__":
  9. main()
  10. '''
  11. thread id = 1
  12. thread id = 2
  13. thread id = 5
  14. thread id = 3
  15. thread id = 6
  16. thread id = 4
  17. thread id = 9
  18. thread id = 8
  19. thread id = 7
  20. '''
  • 通过创建Thread类的子类来构造线程,并重写它的run方法
  1. import threading
  2. import time
  3. # 定义线程子类
  4. class MyThread(threading.Thread):
  5. def __init__(self): #, func, args, name=''):
  6. threading.Thread.__init__(self)
  7. #self.func = func
  8. #self.args = args
  9. #self.name = name
  10. def run(self):
  11. print("starting", self.name)
  12. def main():
  13. t1 = MyThread()
  14. t1.start()
  15. t2 = MyThread()
  16. t2.start()
  17. if __name__ == "__main__":
  18. main()
  19. '''
  20. starting Thread-1
  21. starting Thread-2
  22. '''

4、比较二种创建线程对象

我们用Thread子类程序来模拟航班售票系统,实现二个售票窗口发售某班次航班的10张机票,一个售票窗口用一个线程来表示。

  1. import threading
  2. import time
  3. # 定义线程子类
  4. class MyThread(threading.Thread):
  5. tickets = 10
  6. def __init__(self):
  7. threading.Thread.__init__(self)
  8. def run(self):
  9. while(1):
  10. if(self.tickets>0):
  11. self.tickets = self.tickets-1
  12. print(self.name,"售机票售出第",self.tickets, " 号")
  13. else:
  14. exit()
  15. def main():
  16. t1 = MyThread()
  17. t1.start()
  18. t2 = MyThread()
  19. t2.start()
  20. if __name__ == "__main__":
  21. main()
  22. '''
  23. Thread-1 售机票售出第 9 号
  24. Thread-1 售机票售出第 8 号
  25. Thread-1 售机票售出第 7 号
  26. Thread-2 售机票售出第 9 号
  27. Thread-1 售机票售出第 6 号
  28. Thread-2 售机票售出第 8 号
  29. Thread-1 售机票售出第 5 号
  30. Thread-2 售机票售出第 7 号
  31. Thread-1 售机票售出第 4 号
  32. Thread-2 售机票售出第 6 号
  33. Thread-1 售机票售出第 3 号
  34. Thread-2 售机票售出第 5 号
  35. Thread-1 售机票售出第 2 号
  36. Thread-2 售机票售出第 4 号
  37. Thread-1 售机票售出第 1 号
  38. Thread-1 售机票售出第 0 号
  39. Thread-2 售机票售出第 3 号
  40. Thread-2 售机票售出第 2 号
  41. Thread-2 售机票售出第 1 号
  42. Thread-2 售机票售出第 0 号
  43. '''

从运行结果中可以看到,每张机票被卖了2次,即2个线程各自卖10张机票,而不是去卖共同的10张机票。为什么会这样呢?我们需要的是,多个线程去处理同一资源,一个资源只能对应一个对象。而在上面的程序中,我们创建了2个MyThread对象,每个MyThread对象中都有10张机票,每个线程都在独立地处理各自的资源。

我们用Thread类的构造函数创建的线程程序来模拟航班售票系统,实现二个售票窗口发售某班次航班的10张机票,一个售票窗口用一个线程来表示。

  1. import threading
  2. global tickets
  3. tickets= 11
  4. def fun(i):
  5. global tickets
  6. while(tickets>1):
  7. tickets = tickets-1
  8. print("第", i,"售机票窗口售出第",tickets, " 号")
  9. def main():
  10. for i in range(1,3):
  11. t = threading.Thread(target=fun, args=(i,))
  12. t.start()
  13. if __name__ == "__main__":
  14. main()
  15. '''
  16. 第 1 售机票窗口售出第 10 号
  17. 第 1 售机票窗口售出第 9 号
  18. 第 1 售机票窗口售出第 8 号
  19. 第 1 售机票窗口售出第 6 号
  20. 第 2 售机票窗口售出第 7 号
  21. 第 1 售机票窗口售出第 5 号
  22. 第 2 售机票窗口售出第 4 号
  23. 第 1 售机票窗口售出第 3 号
  24. 第 2 售机票窗口售出第 2 号
  25. 第 1 售机票窗口售出第 1 号
  26. '''

在上面的程序中,创建了2个线程,每个线程调用的是同一个Thread对象中的fun()方法,访问的是同一个对象中的变量(tickets)的实例。因此,这个程序能满足我们的要求。

5、线程同步

多线程使用不当可能造成数据混乱。例如,两个线程都要访问同一个共享变量,一个线程读这个变量的值并在这个值的基础上完成某些操作,但就在此时,另一个线程改变了这个变量值,但第一个线程并不知道,这可能造成数据混乱。

下面模拟二个用户从银行取款的操作造成数据混乱的一个例子。

设计一个模拟用户从银行取款的应用程序。设某银行帐户存款额的初值是2000元,用线程模拟两个用户从银行取款的情况。

  1. import threading
  2. import time
  3. #定义银行帐户类
  4. class Mbank:
  5. global sum
  6. sum=2000
  7. def take(k):
  8. global sum
  9. temp=sum
  10. temp=temp - k
  11. time.sleep(0.2)
  12. sum = temp
  13. print("sum=",sum)
  14. # 模拟用户取款的线程子类
  15. class MyThread(threading.Thread):
  16. tickets = 10
  17. def __init__(self):
  18. threading.Thread.__init__(self)
  19. def run(self):
  20. for i in range(1,5): #循环四次
  21. Mbank.take(100)
  22. def main():
  23. t1 = MyThread()
  24. t1.start()
  25. t2 = MyThread()
  26. t2.start()
  27. if __name__ == "__main__":
  28. main()
  29. '''
  30. sum= 1900
  31. sum= 1900
  32. sum= 1800
  33. sum= 1800
  34. sum= 1700
  35. sum= 1700
  36. sum= 1600
  37. sum= 1600
  38. '''

我们该如何解决呢?

6、线程同步的方法

使用同步线程是为了保证在一个进程中多个线程能协同工作,所以线程的同步很重要。所谓线程同步就是在执行多线程任务时,一次只能有一个线程访问共享资源,其他线程只能等待,只有当该线程完成自己的执行后,另外的线程才可以进入。

使用Thread对象的LockRlock可以实现简单的线程同步,这两个对象都有acquire()方法和release()方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquirerelease方法之间。

用线程同步的方法重新设计用户从银行取款的应用程序。

  1. import threading
  2. import time
  3. threadLock = threading.Lock() #创建一个锁对象
  4. #定义银行帐户类
  5. class Mbank:
  6. global sum
  7. sum=2000
  8. def take(k):
  9. global sum
  10. temp=sum
  11. temp=temp - k
  12. time.sleep(0.2)
  13. sum = temp
  14. print("sum=",sum)
  15. # 模拟用户取款的线程子类
  16. class MyThread(threading.Thread):
  17. tickets = 10
  18. def __init__(self):
  19. threading.Thread.__init__(self)
  20. def run(self):
  21. for i in range(1,5):
  22. threadLock.acquire() #获得锁
  23. Mbank.take(100)
  24. threadLock.release() #释放锁
  25. def main():
  26. t1 = MyThread()
  27. t1.start()
  28. t2 = MyThread()
  29. t2.start()
  30. if __name__ == "__main__":
  31. main()
  32. '''
  33. sum= 1900
  34. sum= 1800
  35. sum= 1700
  36. sum= 1600
  37. sum= 1500
  38. sum= 1400
  39. sum= 1300
  40. sum= 1200
  41. '''

二、异常处理

1、异常

不严重的错误我们称之异常。(如:3/0

Python标准常见异常(网上摘抄滴):

异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

2、异常的捕捉与处理

(1)使用try...except语句:

  1.   try:
  2. <被检测的语句块>
  3. except <异常类型名称>:
  4. <处理异常的语句块>

例如:元组下标越界引发异常

  1. s=[1,2,3,4,5]
  2. try:
  3. print(s[5])
  4. except IndexError:
  5. print("索引出界")
  6. '''
  7. 发生异常原因:索引出界
  8. '''

(2)使用try...except...else语句:

  1. try:
  2. <被检测的语句块>
  3. except <异常类型名称>:
  4. <处理异常的语句块>
  5. else
  6. <无异常时执行的语句块>

例如:编写程序,从键盘输入1,2,……,5中的一个数字,否则,当输入其他数字或字符则提示为异常。

  1. s=[1,2,3,4,5]
  2. while True:
  3. try:
  4. i = eval(input('input:'))
  5. print(s[i])
  6. except IndexError:
  7. print("发生异常原因:索引出界")
  8. break
  9. except NameError:
  10. print("发生异常原因:不是数字")
  11. break
  12. except KeyboardInterrupt:
  13. print("发生异常原因:用户中断输入")
  14. break
  15. else:
  16. pass

(3)带有finally子句的try语句:

  1. s=input("请输入你的年龄:")
  2. if s =="":
  3. raise Exception("输入不能为空.")
  4. try:
  5. i=int(s)
  6. except Exception as err:
  7. print(err)
  8. finally:
  9. print("Goodbye!")

三、正则表达式

1、字符匹配与匹配模式

(1)字符匹配

我们先从简单的问题开始。假设要搜索一个包含字符“cat”的字符串,搜索用的子字符串就是“cat”。如果搜索对大小写不敏感,单词“catalog”、“Catherine”、“sophisticated”都可以匹配。也就是说:

子字符串:cat

匹配:catalog、Catherine、sophisticated

(2)匹配模式

例如,使用?*通配符来查找硬盘上的文件。?通配符匹配文件名中的1个字符,而*通配符匹配多个字符。这时,?*通配符就是一种匹配模式。

比如,data?.dat这样的模式将查找下列文件:

data.dat

data1.dat

data2.dat

datax.dat

dataN.dat

若使用*字符代替?字符扩大了找到的文件的数量。data*.dat匹配下列所有文件:

data.dat

data1.dat

data2.dat

data12.dat

datax.dat

dataXYZ.dat

2、正则表达式的规则

正则表达式是一种可以用于模式匹配替换的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。一个正则表达式就是由普通的字符(例如字符‘a’~‘z’)以及特殊字符(称为“元字符”)组成的文字模式。该模式用以描述在查找文字主体时待匹配的一个或多个字符串。

正则表达式的使用,可以通过简单的办法来实现强大的功能。

下面先看一个简单的用特殊字符(元字符)表示正则表达式规则的示例:

^ [ 0 – 9 ] + abc$

其中:

  • ^ 匹配字符串的开始位置。

  • [0-9]+ 匹配多个数字, [0-9]匹配单个数字,+匹配一个或者多个。

  • abc$匹配字母 abc 并以“abc”结尾

  • $为匹配输入字符串的结束位置。

该规则表示,需要匹配以数字开头并以“abc”结尾的字符串。

编写程序,匹配以数字开头,并以“abc”结尾的字符串。

  1. import re
  2. str = r"123abc" # 需要匹配的源文本
  3. p1 = r"^[0-9]+abc$" # 编写正则表达式规则
  4. patt1 = re.compile(p1) # 编译正则表达式
  5. matc1 = re.search(patt1, str) # 在源文本看搜索符合正则表达式的部分
  6. print(matc1.group(0)) # 123abc

匹配的流程如下:

3、正则表达式re模块的方法

(1)re模块的方法

正则表达式re模块提供了正则表达式操作所需要的方法,利用这些方法,可以很方便地得到匹配结果。

(2)模式对象的方法

  • group():

group()用于获取子模式(组)的匹配项。

例如:

  1. pat = re.compile(r'www\.(.*)\.(.*)') # 用()表示1个组,这里定义2个组
  2. m = pat.match('www.dxy.com')
  3. m.group() # 默认值为0,表示匹配整个字符串,返回'www.dxy.com'
  4. m.group(1) # 返回给定组1匹配的子字符串'dxy'
  5. m.group(2) # 返回给定组2匹配的子字符串'com'
  • start():

start()为指定组匹配项的开始位置

例如:

  1. m.start(2) # 组2开始的索引,返回值为8
  • end():

end()为指定组匹配项的结束位置

例如:

  1. m.end(2) # 组2结束的索引,返回值为11

小案例演示:

编译正则表达式,创建模式对象示例

  1. import re
  2. pat=re.compile('A') #编译正则表达式
  3. m=pat.search('CBA') #等价于 re.search('A','CBA')
  4. print(m)
  5. #匹配到了,返回<_sre.SRE_Match object: span=(2, 3)>
  6. m=pat.search('CBD')
  7. print(m)
  8. #没有匹配到,返回None(False)

在一个字符串中查找子串示例

  1. #第一步,要引入re模块
  2. import re
  3. #第二步,调用模块函数
  4. a = re.findall("我在吃大西瓜呢", "博客园的我在吃大西瓜呢正在准备考研,他要考计算机专业")
  5. print(a) #以列表形式返回匹配到的字符串

三、一个案例

应用多线程,编写一个“幸运大转盘”抽奖游戏程序。

  1. ######################
  2. #幸运大转盘 #
  3. ######################
  4. import tkinter
  5. import time
  6. import threading
  7. root = tkinter.Tk()
  8. root.title('“幸运大转盘”抽奖游戏')
  9. root.minsize(300,300)
  10. btn1 = tkinter.Button(text = '奔驰',bg = 'red')
  11. btn1.place(x = 20, y = 20, width = 50, height = 50)
  12. btn2 = tkinter.Button(text = '宝马',bg = 'white')
  13. btn2.place(x = 90, y = 20, width = 50, height = 50)
  14. btn3 = tkinter.Button(text = '奥迪',bg = 'white')
  15. btn3.place(x = 160, y = 20, width = 50, height = 50)
  16. btn4 = tkinter.Button(text = '日产',bg = 'white')
  17. btn4.place(x = 230, y = 20, width = 50, height = 50)
  18. btn5 = tkinter.Button(text = '宾利',bg = 'white')
  19. btn5.place(x = 230, y = 90, width = 50, height = 50)
  20. btn6 = tkinter.Button(text = '劳斯',bg = 'white')
  21. btn6.place(x = 230, y = 160, width = 50, height = 50)
  22. btn7 = tkinter.Button(text = '奇瑞',bg = 'white')
  23. btn7.place(x = 230, y = 230, width = 50, height = 50)
  24. btn8 = tkinter.Button(text = '吉利',bg = 'white')
  25. btn8.place(x = 160, y = 230, width = 50, height = 50)
  26. btn9 = tkinter.Button(text = '大众',bg = 'white')
  27. btn9.place(x = 90, y = 230, width = 50, height = 50)
  28. btn10 = tkinter.Button(text = '沃尔沃',bg = 'white')
  29. btn10.place(x = 20, y = 230, width = 50, height = 50)
  30. btn11 = tkinter.Button(text = '红旗',bg = 'white')
  31. btn11.place(x = 20, y = 160, width = 50, height = 50)
  32. btn12 = tkinter.Button(text = '长城',bg = 'white')
  33. btn12.place(x = 20, y = 90, width = 50, height = 50)
  34. #将所有选项组成列表
  35. carlist = [btn1,btn2,btn3,btn4,btn5,btn6,btn6,btn7,btn8,btn9,btn10,btn11,btn12]
  36. #是否开始循环的标志
  37. isloop = False
  38. def round():
  39. #判断是否开始循环
  40. if isloop == True:
  41. return
  42. #初始化计数 变量
  43. i = 0
  44. #死循环
  45. while True:
  46. time.sleep(0.1)
  47. #将所有的组件背景变为白色
  48. for x in carlist:
  49. x['bg'] = 'white'
  50. #将当前数值对应的组件变色
  51. carlist[i]['bg'] = 'red'
  52. #变量+1
  53. i += 1
  54. #如果i大于最大索引直接归零
  55. if i >= len(carlist):
  56. i = 0
  57. if functions ==True :
  58. continue
  59. else :
  60. break
  61. #“开始”按钮事件:建立一个新线程的函数。
  62. def newtask():
  63. global isloop
  64. global functions
  65. #建立新线程
  66. t = threading.Thread(target= round)
  67. #开启线程运行
  68. t.start()
  69. #设置程序开始标志
  70. isloop = True
  71. #是否运行的标志
  72. functions = True
  73. #“停止”按钮事件:停止循环
  74. def stop():
  75. global isloop
  76. global functions
  77. functions = False
  78. isloop = False
  79. #开始按钮
  80. btn_start = tkinter.Button(root,text = '开始',command = newtask)
  81. btn_start.place(x = 90, y = 120, width = 50, height = 50)
  82. btn_stop = tkinter.Button(root,text = '停止',command = stop)
  83. btn_stop.place(x = 160, y = 120, width = 50, height = 50)
  84. root.mainloop()

四、大数据预备学习

下节课要讲,很是期待啊,大学都是学Javaweb了,从来没有尝试去接触大数据学习。

大数据(Big Data)有5大特性:volume(大量)、velocity(高速)、variety(多样)、value(低价值密度)、veracity(真实性)

一些准备,下载以下三个库,网速慢就找三方库:

  1. pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 库名

数据挖掘: jieba (分析《三国演义》人物出场次数统计)

数据可视化:numpypandasmatplotlib (霍兰德“人格分析”雷达图)

虽然网上可能很早就有了,但是毕竟是入门,值得期待。

Python课程笔记(十一)的更多相关文章

  1. Python课程笔记(一)

    由于新冠状病毒的爆发,不得不在家里上网课,开课已经两个礼拜了,今天上完Python课后,准备整理一下最近学习Python的笔记. 人生苦短,我用Python 一.Hello World 初学一门新的语 ...

  2. Python课程笔记(十)

    不陌生,之前学习一个开源SpringBoot项目,Mysql5.5更换到5.7搞得头疼. 数据库连接的坑之前写的IDEA系列连接会遇到的问题.课程代码 今天上课就主要学习了python如何连接mysq ...

  3. Python课程笔记(九)

    本次课程主要学习了Excel和JSON格式的一些读写操作.课程代码 一.Excel数据读写操作 1.安装模块 pip install xlrd pip install xlwt 网不好可以采用三方库: ...

  4. Python课程笔记(八)

    一些简单的文件操作,学过linux的话理解感觉不会很难.课程代码 一.OS 目录方法 这个模块提供了一种方便的使用操作系统函数的方法 函数 说明 os.mkdir("path") ...

  5. Python课程笔记(六)

    今天上课补上了上次未学完比较重点的鼠标和键盘事件,同时开始学习运用turtle进行绘图. 本次课程的代码: https://gitee.com/wang_ming_er/python_course_l ...

  6. Python课程笔记 (五)

    今天主要学习图形用户界面,更多的还是要我们自己去实际操作,课仿佛上了一半就完了,分享一下课程(这里在SixthClass)的源码: https://gitee.com/wang_ming_er/pyt ...

  7. python 学习笔记十一 SQLALchemy ORM(进阶篇)

    SqlAlchemy ORM SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据A ...

  8. Python学习笔记十一:模块

    标准库(内置模块) time与datetime 模块 时间表示方式 1.时间戳 2.格式化的字符串 3.元组形式 时间戳就是一个秒数 x=time.time(),从1970年1月1日0时0分0秒到现在 ...

  9. python课程笔记

    python变量原理:以数值为主,数字存储在内存中,分配给不同的变量.与C刚好相反 Python中,有3种内建的数据结构:列表.元组和字典.1.列表     list是处理一组有序项目的数据结构,即你 ...

随机推荐

  1. python库--tensorflow--RNN(循环神经网络相关)

    类/方法 返回值类型 参数 说明 tf.contrib.rnn① / tf.nn.rnn_cell② .RNNCell() 实例r 看不懂 trainable=True   name=None   d ...

  2. ThinkCMF5.1主要特性

    更改框架协议为MIT,让你更自由地飞 基于ThinkPHP 5.1重构,但核心代码兼容5.0版本,保证老用户最小升级成本 增加对swoole支持,同时支持swoole协程和全同步模式(请单独安装扩展) ...

  3. 使用Git上传项目到GitHub仓库

    GitHub账号注册很长时间了,但是没怎么上传过东西.今天学习如何利用Git工具将代码上传到GitHub,了解了一些常用命令 $ git config --global user.name " ...

  4. Loadrunner拼装唯一值方法

    由于Loadrunner函数有限性,唯一值需要几个函数的字符串进行拼装,可实现流水号.订单号等等数值的唯一性.具体可见下列方法: 方法一: char OraderID[15];srand(time{N ...

  5. PHP中的PDO对象操作学习(一)初始化PDO及原始SQL语句操作

    PDO 已经是 PHP 中操作数据库事实上的标准.包括现在的框架和各种类库,都是以 PDO 作为数据库的连接方式.基本上只有我们自己在写简单的测试代码或者小的功能时会使用 mysqli 来操作数据库. ...

  6. mysql5.7执行sql语句提示Expression #1 of ORDER BY clause is not in GROUP BY

    mysql 新版本出现group by 语句不兼容问题 [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause ...

  7. html阴影 box-shadow

    右下阴影 div { box-shadow: 10px 10px 5px #888888; }四周阴影 div { box-shadow: 0 0 5px #888888; } div {box-sh ...

  8. 网络IO模型与Reactor模式

    一.三种网络IO模型: 分类: BIO 同步的.阻塞式 IO NIO 同步的.非阻塞式 IO AIO 异步非阻塞式 IO 阻塞和同步的概念: 阻塞:若读写未完成,调用读写的线程一直等待 非阻塞:若读写 ...

  9. WPF进阶技巧和实战03-控件(5-列表、树、网格03)

    数据视图 数据视图是在后台工作的,用于协调绑定数据的集合.使用数据视图可以添加导航逻辑.实现数据过滤.排序.分组. 当将集合或者DataTable绑定到ItemsControl控件时,会不加通告地在后 ...

  10. Java——this关键字总结

    一.this关键字的使用 1.当同类型的对象a和b,调用相同的方法method()时,为了区分该方法是被a调用还是被b调用 如下代码中,: class Banana { void method(int ...