質問するログイン新規登録

回答編集履歴

3

追記

2018/05/06 14:07

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -6,4 +6,77 @@
6
6
  要件が変わって`sys.exit()`ではなく一連の処理(タスク)を途中でキャンセルしたくなったら`ProcessPoolExecutor`になります。
7
7
 
8
8
  そして、ファイルの書き出し部分に関しては外部からキャンセルされてもファイル内容が破損しないように
9
- [tempファイル](https://docs.python.jp/3/library/tempfile.html)と[os.replace](https://docs.python.jp/3/library/os.html#os.replace)を使ったアトミックな書き出し処理に変更してくださいな。
9
+ [tempファイル](https://docs.python.jp/3/library/tempfile.html)と[os.replace](https://docs.python.jp/3/library/os.html#os.replace)を使ったアトミックな書き出し処理に変更してくださいな。
10
+
11
+ ---
12
+ 厳密にキャンセルしている訳ではないですが、ブロッキングの方だけ回避する方法を。
13
+ 1,executor.submitで別タスクを実行
14
+ 2,閉じるボタンやexitボタンを押下した時は、画面を非表示(withdraw)にする。
15
+
16
+ 以下のコードはmax_workers=1に指定しているので、並列度が1です、
17
+ この場合だと同じファイルでも並列に実行されることが起こりえないため問題ないかと。
18
+
19
+
20
+ ProcessPoolExecutorの
21
+ ```Python
22
+ # -*- coding: utf-8 -*-
23
+ from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, Future, as_completed
24
+ from contextlib import closing
25
+ from threading import current_thread, get_ident
26
+ from random import randint
27
+ import tkinter as tk
28
+ import sys
29
+ from time import sleep
30
+ import requests
31
+
32
+
33
+ def on_application_exit():
34
+ # Windowを閉じた時に行いたい処理
35
+ sys.exit(0)
36
+
37
+
38
+ # max_workersは並列度
39
+ executor = ProcessPoolExecutor(max_workers=1)
40
+
41
+
42
+ def hard_task(url: str, seconds: int):
43
+ print(f'tid:{get_ident()}, {current_thread().getName()}, {seconds}')
44
+ sleep(seconds)
45
+ print(f'Wake up{seconds}')
46
+ r = requests.get(url)
47
+ # os.replaceを使ってアトミックに書き出してくださいな。
48
+ with open('yahoo.txt', 'a') as f:
49
+ f.write(r.text)
50
+
51
+
52
+ class MyFrame(tk.Frame):
53
+ def __init__(self, root):
54
+ super().__init__(root)
55
+ self.pack()
56
+ self.btn_task = tk.Button(self, text='task', command=self.task)
57
+ self.btn_task.pack()
58
+ self.btn_exit = tk.Button(self, text='exit', command=on_application_exit)
59
+ self.btn_exit.pack()
60
+
61
+ def close(self):
62
+ self.master.withdraw()
63
+
64
+ def task(self):
65
+ seconds = randint(2, 5)
66
+ url = 'https://www.yahoo.co.jp'
67
+ task = executor.submit(hard_task, url, seconds)
68
+
69
+
70
+ def main() ->None:
71
+ root = tk.Tk()
72
+ root.title("ProcessPoolExecutor")
73
+ root.protocol("WM_DELETE_WINDOW", on_application_exit)
74
+ root.geometry("400x200")
75
+ with closing(MyFrame(root)) as f:
76
+ root.mainloop()
77
+
78
+
79
+ if __name__ == '__main__':
80
+ main()
81
+
82
+ ```

2

追記

2018/05/06 14:07

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -1,9 +1,9 @@
1
- [wxpythonでボタンなどからイベント実行後、GUIをフリーズさせたくない](https://teratail.com/questions/122922)
1
+ 過去の質問で参考になるもの→[wxpythonでボタンなどからイベント実行後、GUIをフリーズさせたくない](https://teratail.com/questions/122922)
2
2
 
3
- キャンセルの要件によるのですが、
3
+ キャンセルの要件によるのですが、
4
4
  スクリプトを終了したい=`sys.exit()`ならば、ボタン実行時の処理を`Tread`または`ThreadPoolExecutor`に流す形にすれば良いかと。
5
5
 
6
- `sys.exit()`ではなく一連の処理(タスク)を途中でキャンセルしたくなったら`ProcessPoolExecutor`になります。
6
+ 要件が変わって`sys.exit()`ではなく一連の処理(タスク)を途中でキャンセルしたくなったら`ProcessPoolExecutor`になります。
7
7
 
8
- そして、ファイルの書き出し部分に関しては外部からキャンセルされても大丈夫なように
8
+ そして、ファイルの書き出し部分に関しては外部からキャンセルされてもファイル内容が破損しように
9
- [tempファイル](https://docs.python.jp/3/library/tempfile.html)と[os.replace](https://docs.python.jp/3/library/os.html#os.replace)を使ったアトミック処理に変更してくださいな。
9
+ [tempファイル](https://docs.python.jp/3/library/tempfile.html)と[os.replace](https://docs.python.jp/3/library/os.html#os.replace)を使ったアトミックな書き出し処理に変更してくださいな。

1

追記

2018/05/06 09:37

投稿

umyu
umyu

スコア5846

answer CHANGED
@@ -3,7 +3,7 @@
3
3
  キャンセルの要件によるのですが、
4
4
  スクリプトを終了したい=`sys.exit()`ならば、ボタン実行時の処理を`Tread`または`ThreadPoolExecutor`に流す形にすれば良いかと。
5
5
 
6
- `sys.exit()`ではなく処理自体を途中でキャンセルしたくなったら`ProcessPoolExecutor`になります。
6
+ `sys.exit()`ではなく一連の処理(タスク)を途中でキャンセルしたくなったら`ProcessPoolExecutor`になります。
7
7
 
8
8
  そして、ファイルの書き出し部分に関しては外部からキャンセルされても大丈夫なように
9
9
  [tempファイル](https://docs.python.jp/3/library/tempfile.html)と[os.replace](https://docs.python.jp/3/library/os.html#os.replace)を使ったアトミック処理に変更してくださいな。