1

Pythonでアプリエンジンを使用しています

値のリストで行う毎日のタスクがあります。これらの値は、ターゲット プロパティの下の「プロジェクト」値に格納されます。

myproject1.targets=['foo','bar','foo2','bar2','foo3','bar3','foo4','bar4','foo5','bar5']

url_to_my_worker私の目標は、値をパラメーターとして使用して、値ごとに url: への呼び出しをキューに入れることです。

現在、データベースにはプロジェクト オブジェクトが 1 つしかありません。

各プロファイル オブジェクトに対して基本的に schedule_daily_profile_tasks をエンキューする schedule_daily_projects_tasks を実行します。

class schedule_daily_projects_tasks(webapp.RequestHandler):
    def post(self):
        key=self.request.get('key')
        pro=project.get(key)
        profiles=my_profile.gql("WHERE project=:1",pro)
        logging.info(profiles)
        for profile in profiles:
            taskqueue.add(url='/control/schedule_daily_profile_tasks', params={'key': profile.key()})

次に、プロファイルごとに「schedule_daily_profile_tasks」を実行します。

class schedule_daily_profile_tasks(webapp.RequestHandler):
    def post(self):
        key=self.request.get('key')
        profile=my_profile.get(key)
        pro=profile.project
        for i in range(1, 6):
            now=datetime.now()
            tim=datetime(year=now.year, month=now.month, day=now.day, hour=8+i)
            screen_name=pro.targets.pop()
            taskqueue.add(url='/url_to_my_worker', params={'profk': key, 'screen_name':screen_name}, eta=tim)
            pro.put()

データベースに profile1 から profile5 までの 5 つのプロファイル オブジェクトがあるとします。すべてがうまくいけば、5 つのタスクが「/url_to_my_worker」という URL に次のパラメーターとともにキューに登録されます。

1) params={'profk': profile1.key(), 'screen_name':'bar5'}
2) params={'profk': profile2.key(), 'screen_name':'foo5'}
3) params={'profk': profile3.key(), 'screen_name':'bar4'}
4) params={'profk': profile4.key(), 'screen_name':'foo4'}
5) params={'profk': profile5.key(), 'screen_name':'bar3'}

しかし、代わりに、私は得る:

1) params={'profk': profile1.key(), 'screen_name':'bar5'}
2) params={'profk': profile2.key(), 'screen_name':'bar5'}
3) params={'profk': profile3.key(), 'screen_name':'bar5'}
4) params={'profk': profile4.key(), 'screen_name':'bar5'}
5) params={'profk': profile5.key(), 'screen_name':'bar5'}

タスクの実行速度が速すぎると思われるため、n°1 が「ポップ」する前に n°2 が開始されます。したがって、myproject1.targets の値は同じです。

リスト内の各値が一度だけ使用されるようにするにはどうすればよいですか?

どうもありがとう

4

4 に答える 4

2

発生している問題は、多かれ少なかれ、説明したとおりです。同じデータストア オブジェクトを同時に変更しようとしている複数のタスクをキューに入れました。トランザクションを使用していないため、複数のタスクが同じデータを取得し、同じ操作を実行してから、互いの結果を上書きすることになります。

これを回避するためにデータストア トランザクションを使用することもできますが、1 つのタスクのみが各データストア エンティティを変更するようにタスクを再構築することをお勧めします。そうすれば、同期やトランザクションの問題について心配する必要はありません。

于 2012-07-16T03:12:40.640 に答える
1

タスクをバッチとして追加することを検討してください。

targets=pro.targets
tasks=[]
...
  screen_name=targets.pop()
  tasks.append(taskqueue.Task(url='/url_to_my_worker', params={'profk': key, 'screen_name':screen_name}, eta=tim))
...
pro.put()
taskqueue.Queue().add(tasks)

max_concurrent_requests を 1 に指定する queue.yaml を作成することで、特定のキューでのタスクの同時実行を回避できることに注意してください。

queue:
- name: default
  max_concurrent_requests: 1
于 2012-07-16T00:30:31.307 に答える
0

プロジェクト recs に膨大な数のプロファイル要素がない場合: Schedule_daily_projects_tasks() は、すべてのプロファイル要素をシリアル化された文字列に結合できます。その文字列をパラメーターとしてタスク キューに渡します。各タスク プロセスは文字列から 1 つの要素を取り出して処理し、例外が発生しない場合はシリアル化された短い文字列を使用してタスクをキューに入れます。同じエンティティに対して更新を行っている場合は、2 秒程度の時間遅延でタスクをキューに入れます。これは、コストを抑えることができるタスク キューを処理するために起動されるインスタンスの数を調整するのにも役立ちます。

于 2012-07-16T22:49:25.010 に答える
0

Python には、スレッドセーフな Queue ライブラリ モジュールが組み込まれています。

http://docs.python.org/library/queue.html

Queue モジュールは、マルチ プロデューサー、マルチ コンシューマー キューを実装します。複数のスレッド間で情報を安全に交換する必要がある場合、スレッド化されたプログラミングで特に役立ちます。このモジュールの Queue クラスは、必要なすべてのロック セマンティクスを実装します。これは、Python でスレッドがサポートされているかどうかによって異なります。threading モジュールを参照してください。

pop() が呼び出されたときに、ロックが解除されるまで単純にブロックするようにすることができます。

編集:リンクされたサンプルページは、キューモジュールを使用して作業を行います。

import Queue
targets = ['foo','bar','foo2','bar2','foo3','bar3','foo4','bar4','foo5','bar5']
queue = Queue.LifoQueue() # Last in first out
for target in targets:
    queue.put(target)
myproject1.targets = queue
##########################
class schedule_daily_profile_tasks(webapp.RequestHandler):
    ....
    screen_name=pro.targets.get(block=true)
于 2012-07-15T17:24:22.910 に答える