Popen / Wait - 等待永远不会结束

时间:2021-07-20 14:58:24

标签: python python-3.x subprocess

import sys
import os
from subprocess import Popen, PIPE, STDOUT

# Transfer Database
print ('Transferring from ' + mysql_source_database)
mysql = Popen(f"mysql -h {mysql_dest_host} -P 3306 -u {mysql_dest_username} -p{mysql_dest_pw} {mysql_dest_database}".split(), stdin=PIPE, stdout=PIPE)
dbnamerewrite = Popen(f"sed s/{mysql_source_database}/{mysql_dest_database}/g".split(), stdin=PIPE, stdout=mysql.stdin)
mysqldump = Popen(f"mysqldump --set-gtid-purged=OFF --column-statistics=0 -h {mysql_source_host} -P 3306 -u {mysql_source_username} -p{mysql_source_pw} {mysql_source_database}".split(), stdout=dbnamerewrite.stdin)
mysql_stdout = mysql.communicate()[0]
mysqldump.wait()

上面的代码做了我想要的,但从未停止等待。有谁知道如何解决等待。如果我在 SQL 工作完成后按 ctrl-c,这是给定的错误:

^CERROR 1064 (42000) at line 3829: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 3
Traceback (most recent call last):
  File "test.py", line 19, in <module>
    mysql_stdout = mysql.communicate()[0]
  File "/usr/lib/python3.8/subprocess.py", line 1028, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "/usr/lib/python3.8/subprocess.py", line 1868, in _communicate
    ready = selector.select(timeout)
  File "/usr/lib/python3.8/selectors.py", line 415, in select
    fd_event_list = self._selector.poll(timeout)
KeyboardInterrupt

1 个答案:

答案 0 :(得分:3)

有一件事是您应该放弃对 import scrapy class QuotesSpider(scrapy.Spider): name = "quotes" start_urls = [ 'https://boo.ua/catalog/smartfony/huawei-p30-lite-4-128gb--mar-lx1a-/', 'https://boo.ua/catalog/smartfony/huawei-p20-2018-4-128gb-black-eml-l29/', ] def parse(self, response): for quote in response.xpath('(descendant::div[@class="col-lg-5 model__spec"])'): quote = quote.getall() quote = [i.replace("\t", "").replace("\n", "") for i in quote] yield { 'specification': quote } 的显式调用。根据{{​​3}}:

<块引用>

注意:这将在使用 mysqldump.wait()stdout=PIPE 时死锁,并且子进程向管道生成足够的输出,从而阻止等待操作系统管道缓冲区接受更多数据。使用管道时使用 docs 来避免这种情况。

Popen.communicate() 在这种情况下就足够了,因为在管道上的所有元素都发送一个 EOF 之前,它不会收到 EOF。所以stderr=PIPE直接返回意味着其他两个进程都完成了。

另一个问题是,根据您拥有的进程的顺序,您必须以相反的顺序对所有进程调用 mysql.communicate() 才能使数据流过管道。一种解决方案就是这样做:

communicate

另一种选择是以相反的顺序设置管道,在这种情况下,您只需要db_param = ['-h', mysql_dest_host, '-P', '3306', '-u', mysql_dest_username, f'p{mysql_dest_pw}', mysql_dest_database] mysql = Popen(['mysql'] + db_param, stdin=PIPE, stdout=PIPE) dbnamerewrite = Popen(['sed', f's/{mysql_source_database}/{mysql_dest_database}/g'], stdin=PIPE, stdout=mysql.stdin) mysqldump = Popen(['mysqldump', '--set-gtid-purged=OFF', '--column-statistics=0'] + db_param, stdout=dbnamerewrite.stdin) mysqldump.communicate() dbnamerewrite.communicate() mysql_stdout = mysql.communicate()[0] 执行最后一个过程:

communicate